<?php
if ( ! defined( 'ABSPATH' ) ) exit;

/**
 * VMO Email Compliance: unsubscribe handling.
 */

if (!defined('ABSPATH')) {
    exit;
}

class VMO_Email_Compliance {

    private static $instance = null;

    public static function get_instance() {
        if (!self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct() {
        add_action('rest_api_init', array($this, 'register_routes'));
    }

    public function register_routes() {
        register_rest_route('vmo/v1', '/email/unsubscribe', array(
            'methods' => array('GET', 'POST'),
            'callback' => array($this, 'handle_unsubscribe'),
            'permission_callback' => '__return_true', // Public unsubscribe endpoint — accessed via emailed links; validated by HMAC token in callback
            'args' => array(
                'token' => array(
                    'required' => true,
                    'type' => 'string',
                ),
            ),
        ));
    }

    // --------------------------
    // Unsubscribe tokens
    // --------------------------

    public static function build_unsubscribe_url($token) {
        return add_query_arg(array('token' => rawurlencode($token)), rest_url('vmo/v1/email/unsubscribe'));
    }

    public static function make_unsubscribe_token($install_id, $email, $ttl_seconds = null) {
        $install_id = sanitize_text_field((string) $install_id);
        $email = sanitize_email((string) $email);
        if ($install_id === '' || !$email) {
            return '';
        }

        $ttl_seconds = $ttl_seconds === null ? DAY_IN_SECONDS * 30 : max(300, intval($ttl_seconds));
        $exp = time() + $ttl_seconds;

        $payload = array(
            'v' => 1,
            'install_id' => $install_id,
            'email' => strtolower($email),
            'exp' => $exp,
        );

        $json = wp_json_encode($payload);
        $b64 = self::b64url_encode($json);
        $sig = self::b64url_encode(hash_hmac('sha256', $b64, self::signing_secret(), true));

        return $b64 . '.' . $sig;
    }

    public static function parse_unsubscribe_token($token) {
        $token = (string) $token;
        if ($token === '' || strpos($token, '.') === false) {
            return null;
        }
        list($b64, $sig) = array_pad(explode('.', $token, 2), 2, '');
        if ($b64 === '' || $sig === '') {
            return null;
        }

        $expected = self::b64url_encode(hash_hmac('sha256', $b64, self::signing_secret(), true));
        if (!hash_equals($expected, $sig)) {
            return null;
        }

        $json = self::b64url_decode($b64);
        if ($json === null) {
            return null;
        }
        $payload = json_decode($json, true);
        if (!is_array($payload)) {
            return null;
        }
        if (intval($payload['v'] ?? 0) !== 1) {
            return null;
        }
        if (empty($payload['install_id']) || empty($payload['email']) || empty($payload['exp'])) {
            return null;
        }
        if (time() > intval($payload['exp'])) {
            return null;
        }

        return array(
            'install_id' => sanitize_text_field((string) $payload['install_id']),
            'email' => sanitize_email((string) $payload['email']),
        );
    }

    private static function signing_secret() {
        // Use WP salts; stable across requests and unique per site.
        return wp_salt('vmo_email_compliance');
    }

    private static function b64url_encode($raw) {
        $b64 = base64_encode((string) $raw); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- data encoding
        return rtrim(strtr($b64, '+/', '-_'), '=');
    }

    private static function b64url_decode($b64url) {
        $b64url = (string) $b64url;
        $b64 = strtr($b64url, '-_', '+/');
        $pad = strlen($b64) % 4;
        if ($pad) {
            $b64 .= str_repeat('=', 4 - $pad);
        }
        $raw = base64_decode($b64, true); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- data decoding
        return $raw === false ? null : $raw;
    }

    // --------------------------
    // Suppression logic
    // --------------------------

    public static function get_user_id_for_install($install_id) {
        global $wpdb;
        $install_id = sanitize_text_field((string) $install_id);
        if ($install_id === '') {
            return 0;
        }
        $table = $wpdb->prefix . 'vmo_manager_activations';
        $user_id = $wpdb->get_var($wpdb->prepare(
            "SELECT user_id FROM {$table} WHERE install_id = %s LIMIT 1",
            $install_id
        ));
        return intval($user_id);
    }

    public static function get_contact_id_by_email($user_id, $email) {
        global $wpdb;
        $user_id = intval($user_id);
        $email = sanitize_email((string) $email);
        if ($user_id <= 0 || !$email) {
            return '';
        }
        $contacts = $wpdb->prefix . 'vmo_contacts';
        $contact_id = $wpdb->get_var($wpdb->prepare(
            "SELECT contact_id FROM {$contacts} WHERE user_id = %d AND LOWER(email) = LOWER(%s) LIMIT 1",
            $user_id,
            $email
        ));
        return $contact_id ? sanitize_text_field((string) $contact_id) : '';
    }

    public static function is_email_suppressed_for_install($install_id, $email) {
        $user_id = self::get_user_id_for_install($install_id);
        if ($user_id <= 0) {
            return array('suppressed' => false);
        }
        return self::is_email_suppressed_for_user($user_id, $email);
    }

    public static function is_email_suppressed_for_user($user_id, $email) {
        global $wpdb;
        $user_id = intval($user_id);
        $email = sanitize_email((string) $email);
        if ($user_id <= 0 || !$email) {
            return array('suppressed' => false);
        }

        $contact_id = self::get_contact_id_by_email($user_id, $email);
        if ($contact_id === '') {
            return array('suppressed' => false);
        }

        $prefs = $wpdb->prefix . 'vmo_contact_preferences';
        $row = $wpdb->get_row($wpdb->prepare(
            "SELECT do_not_contact, unsubscribe_date, email_subscribed, marketing_emails FROM {$prefs} WHERE user_id = %d AND contact_id = %s LIMIT 1",
            $user_id,
            $contact_id
        ), ARRAY_A);

        if (!$row) {
            return array('suppressed' => false);
        }

        $do_not_contact = !empty($row['do_not_contact']);
        $unsubscribed = !empty($row['unsubscribe_date']);
        $email_subscribed = isset($row['email_subscribed']) ? (bool) $row['email_subscribed'] : true;
        $marketing_ok = isset($row['marketing_emails']) ? (bool) $row['marketing_emails'] : true;

        if ($do_not_contact || $unsubscribed || !$email_subscribed || !$marketing_ok) {
            return array(
                'suppressed' => true,
                'reason' => $do_not_contact ? 'do_not_contact' : ($unsubscribed ? 'unsubscribed' : (!$email_subscribed ? 'email_unsubscribed' : 'marketing_disabled')),
            );
        }

        return array('suppressed' => false);
    }

    public static function mark_unsubscribed_for_install($install_id, $email, $reason = 'unsubscribe') {
        $user_id = self::get_user_id_for_install($install_id);
        if ($user_id <= 0) {
            return false;
        }
        return self::mark_unsubscribed_for_user($user_id, $email, $reason);
    }

    public static function mark_unsubscribed_for_user($user_id, $email, $reason = 'unsubscribe') {
        global $wpdb;
        $user_id = intval($user_id);
        $email = sanitize_email((string) $email);
        if ($user_id <= 0 || !$email) {
            return false;
        }
        $contact_id = self::get_contact_id_by_email($user_id, $email);
        if ($contact_id === '') {
            return false;
        }

        $prefs = $wpdb->prefix . 'vmo_contact_preferences';
        $now = current_time('mysql');

        $existing = $wpdb->get_var($wpdb->prepare(
            "SELECT id FROM {$prefs} WHERE user_id = %d AND contact_id = %s LIMIT 1",
            $user_id,
            $contact_id
        ));

        $data = array(
            'email_subscribed' => 0,
            'marketing_emails' => 0,
            'newsletter_subscribed' => 0,
            'do_not_contact' => 1,
            'unsubscribe_date' => $now,
            'preferences_updated' => $now,
            'updated_at' => $now,
        );

        if ($existing) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->update($prefs, $data, array('id' => $existing));
        } else {
            $data['user_id'] = $user_id;
            $data['contact_id'] = $contact_id;
            $data['created_at'] = $now;
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->insert($prefs, $data);
        }

        // Best-effort: log into interactions if table exists.
        $interactions = $wpdb->prefix . 'vmo_contact_interactions';
        if ($wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $interactions)) === $interactions) {
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->insert($interactions, array(
                'user_id' => $user_id,
                'contact_id' => $contact_id,
                'interaction_type' => 'email',
                'interaction_subtype' => 'unsubscribe',
                'direction' => 'inbound',
                'subject' => 'Unsubscribe',
                'summary' => 'Contact unsubscribed via ' . sanitize_text_field($reason),
                'outcome' => 'successful',
                'created_at' => $now,
                'updated_at' => $now,
            ));
        }

        return true;
    }

    // --------------------------
    // REST handlers
    // --------------------------

    public function handle_unsubscribe(WP_REST_Request $request) {
        $token = (string) $request->get_param('token');
        $parsed = self::parse_unsubscribe_token($token);
        if (!$parsed) {
            return new WP_REST_Response('Invalid or expired unsubscribe link.', 400, array('Content-Type' => 'text/plain; charset=UTF-8'));
        }

        $ok = self::mark_unsubscribed_for_install($parsed['install_id'], $parsed['email'], 'one_click');
        if (!$ok) {
            return new WP_REST_Response('Unsubscribe failed (contact not found).', 404, array('Content-Type' => 'text/plain; charset=UTF-8'));
        }

        $html = '<!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Unsubscribed</title></head><body><h2>You are unsubscribed.</h2><p>You will no longer receive marketing emails from this business.</p></body></html>';
        return new WP_REST_Response($html, 200, array('Content-Type' => 'text/html; charset=UTF-8'));
    }
}
