<?php
namespace DS_Plugin;

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

class Protection {
    public static function init() {
        add_filter('ds_user_is_pro', [__CLASS__, 'filter_user_is_pro'], 10, 2);
    }

    public static function filter_user_is_pro($is_pro, $user_id = 0) {
        if ($is_pro) return true;
        $opts = Settings::get();
        $creds = self::ensure_site_credentials($opts);
        if (is_wp_error($creds) || !is_array($creds)) return false;

        $uid = max(0, (int) $user_id);
        if ($uid <= 0 && is_user_logged_in()) {
            $uid = (int) get_current_user_id();
        }

        $api_url = (string) ($creds['api_url'] ?? '');
        $api_token = (string) ($creds['api_token'] ?? '');
        $license_key = (string) ($creds['license_key'] ?? '');
        if ($api_url === '' || $license_key === '') {
            return false;
        }

        $cache_minutes = max(1, (int) ($opts['protection_license_cache_min'] ?? 15));
        $cache_key = self::cache_key_for_actor($uid);
        $cached = get_transient($cache_key);
        if (is_array($cached) && isset($cached['is_pro'])) {
            return !empty($cached['is_pro']);
        }

        $payload = [
            'license_key' => $license_key,
            'site_url' => home_url('/'),
            'domain' => self::site_domain(),
            'instance_id' => self::instance_id(),
            'user_id' => $uid,
            'user_email' => self::user_email($uid),
            'timestamp' => time(),
        ];
        $check = self::remote_post_json(self::endpoint_url($api_url, 'check'), $payload, $api_token);
        if (is_wp_error($check)) return false;
        $remote_is_pro = !empty($check['is_pro']);
        if ($remote_is_pro) {
            $has_activation = !empty($check['activation']) && is_array($check['activation']);
            $can_activate = !empty($check['can_activate']);
            if (!$has_activation && $can_activate) {
                self::remote_post_json(self::endpoint_url($api_url, 'activate'), $payload, $api_token);
            } elseif ($has_activation) {
                self::remote_post_json(self::endpoint_url($api_url, 'heartbeat'), $payload, $api_token);
            }
        }
        set_transient($cache_key, ['is_pro' => $remote_is_pro], $cache_minutes * MINUTE_IN_SECONDS);
        return $remote_is_pro;
    }

    private static function endpoint_url($raw, $type) {
        $u = rtrim((string) $raw, '/');
        if ($u === '') return '';
        if (preg_match('#/v1/license/(check|activate|heartbeat)$#i', $u)) {
            $u = preg_replace('#/(check|activate|heartbeat)$#i', '/' . $type, $u);
            return (string) $u;
        }
        if (preg_match('#/v1$#i', $u)) return $u . '/license/' . $type;
        return $u . '/v1/license/' . $type;
    }

    private static function endpoint_url_trial($raw, $type) {
        $u = rtrim((string) $raw, '/');
        if ($u === '') return '';
        if (preg_match('#/v1/trial/(check|consume)$#i', $u)) {
            $u = preg_replace('#/(check|consume)$#i', '/' . $type, $u);
            return (string) $u;
        }
        if (preg_match('#/v1$#i', $u)) return $u . '/trial/' . $type;
        return $u . '/v1/trial/' . $type;
    }

    private static function endpoint_url_capability($raw, $type) {
        $u = rtrim((string) $raw, '/');
        if ($u === '') return '';
        if (preg_match('#/v1/capability/issue$#i', $u)) {
            return (string) $u;
        }
        if (preg_match('#/v1$#i', $u)) return $u . '/capability/' . $type;
        return $u . '/v1/capability/' . $type;
    }

    private static function endpoint_url_bootstrap($raw) {
        $u = rtrim((string) $raw, '/');
        if ($u === '') return '';
        if (preg_match('#/v1/license/bootstrap$#i', $u)) {
            return (string) $u;
        }
        if (preg_match('#/v1$#i', $u)) return $u . '/license/bootstrap';
        return $u . '/v1/license/bootstrap';
    }

    private static function endpoint_url_bootstrap_install($raw) {
        $u = rtrim((string) $raw, '/');
        if ($u === '') return '';
        if (preg_match('#/v1/license/bootstrap/install$#i', $u)) {
            return (string) $u;
        }
        if (preg_match('#/v1/license/bootstrap$#i', $u)) {
            return $u . '/install';
        }
        if (preg_match('#/v1$#i', $u)) return $u . '/license/bootstrap/install';
        return $u . '/v1/license/bootstrap/install';
    }

    private static function remote_post_json($url, $payload, $api_token = '') {
        if (!is_string($url) || $url === '') {
            return new \WP_Error('ds_bad_license_url', __('Missing license endpoint URL.', 'ds'));
        }
        $args = [
            'timeout' => 8,
            'headers' => [
                'Content-Type' => 'application/json',
            ],
            'body' => wp_json_encode($payload),
        ];
        if ($api_token !== '') {
            $args['headers']['Authorization'] = 'Bearer ' . $api_token;
        }
        $res = wp_remote_post($url, $args);
        if (is_wp_error($res)) return $res;
        $code = (int) wp_remote_retrieve_response_code($res);
        $body = wp_remote_retrieve_body($res);
        $json = json_decode((string) $body, true);
        if ($code < 200 || $code >= 300 || !is_array($json)) {
            $msg = '';
            if (is_array($json) && !empty($json['message'])) {
                $msg = (string) $json['message'];
            }
            if ($msg === '') {
                $msg = __('License endpoint returned invalid response.', 'ds');
            }
            return new \WP_Error('ds_bad_license_response', $msg, [
                'status' => $code,
                'body' => is_array($json) ? $json : [],
                'raw' => (string) $body,
            ]);
        }
        return $json;
    }

    private static function user_email($user_id) {
        if ((int) $user_id <= 0) return '';
        $u = get_user_by('id', (int) $user_id);
        if (!$u || empty($u->user_email)) return '';
        return sanitize_email($u->user_email);
    }

    private static function cache_key_for_actor($user_id) {
        $uid = max(0, (int) $user_id);
        if ($uid > 0) return 'ds_pro_status_u_' . $uid;
        $ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '0.0.0.0';
        return 'ds_pro_status_g_' . md5($ip . '|' . wp_salt('nonce'));
    }

    private static function site_domain() {
        $host = wp_parse_url(home_url('/'), PHP_URL_HOST);
        return is_string($host) ? strtolower($host) : '';
    }

    private static function instance_id() {
        $k = 'ds_protection_instance_id';
        $v = (string) get_option($k, '');
        if ($v !== '') return sanitize_key($v);
        $raw = function_exists('wp_generate_uuid4') ? wp_generate_uuid4() : uniqid('ds', true);
        $id = sanitize_key(str_replace('-', '', (string) $raw));
        if ($id === '') $id = md5(home_url('/') . '|' . wp_salt('auth'));
        update_option($k, $id, false);
        return $id;
    }

    public static function remote_trial_check($action = 'save') {
        $creds = self::ensure_site_credentials(Settings::get());
        if (is_wp_error($creds) || !is_array($creds)) {
            return new \WP_Error('ds_trial_remote_disabled', __('Remote trial check is not configured.', 'ds'));
        }
        $api_url = (string) ($creds['api_url'] ?? '');
        $api_token = (string) ($creds['api_token'] ?? '');
        if ($api_url === '' || $api_token === '') {
            return new \WP_Error('ds_trial_remote_disabled', __('Remote trial check is not configured.', 'ds'));
        }
        $payload = [
            'site_url' => home_url('/'),
            'domain' => self::site_domain(),
            'instance_id' => self::instance_id(),
            'action' => sanitize_key((string) $action),
            'timestamp' => time(),
        ];
        return self::remote_post_json(self::endpoint_url_trial($api_url, 'check'), $payload, $api_token);
    }

    public static function remote_trial_consume($action = 'save') {
        $creds = self::ensure_site_credentials(Settings::get());
        if (is_wp_error($creds) || !is_array($creds)) {
            return new \WP_Error('ds_trial_remote_disabled', __('Remote trial consume is not configured.', 'ds'));
        }
        $api_url = (string) ($creds['api_url'] ?? '');
        $api_token = (string) ($creds['api_token'] ?? '');
        if ($api_url === '' || $api_token === '') {
            return new \WP_Error('ds_trial_remote_disabled', __('Remote trial consume is not configured.', 'ds'));
        }
        $payload = [
            'site_url' => home_url('/'),
            'domain' => self::site_domain(),
            'instance_id' => self::instance_id(),
            'action' => sanitize_key((string) $action),
            'timestamp' => time(),
        ];
        return self::remote_post_json(self::endpoint_url_trial($api_url, 'consume'), $payload, $api_token);
    }

    public static function remote_capability_issue($action = 'save_design') {
        $creds = self::ensure_site_credentials(Settings::get());
        if (is_wp_error($creds) || !is_array($creds)) {
            return new \WP_Error('ds_capability_remote_disabled', __('Remote capability issue is not configured.', 'ds'));
        }
        $api_url = (string) ($creds['api_url'] ?? '');
        $api_token = (string) ($creds['api_token'] ?? '');
        $license_key = (string) ($creds['license_key'] ?? '');
        if ($api_url === '' || $api_token === '') {
            return new \WP_Error('ds_capability_remote_disabled', __('Remote capability issue is not configured.', 'ds'));
        }
        $payload = [
            'action' => sanitize_key((string) $action),
            'site_url' => home_url('/'),
            'domain' => self::site_domain(),
            'instance_id' => self::instance_id(),
            'license_key' => $license_key,
            'timestamp' => time(),
        ];
        return self::remote_post_json(self::endpoint_url_capability($api_url, 'issue'), $payload, $api_token);
    }

    private static function read_install_token_from_file() {
        $candidates = [
            DS_PLUGIN_DIR . 'install-token.json',
            DS_PLUGIN_DIR . 'installer-token.json',
        ];
        foreach ($candidates as $file) {
            if (!is_string($file) || $file === '' || !file_exists($file)) continue;
            $raw = file_get_contents($file);
            if (!is_string($raw) || trim($raw) === '') continue;
            $json = json_decode($raw, true);
            if (!is_array($json)) continue;
            $token = isset($json['install_token']) ? trim((string) $json['install_token']) : '';
            if ($token !== '') return $token;
        }
        return '';
    }

    public static function resolve_install_token($opts = null) {
        $opts = is_array($opts) ? $opts : Settings::get();
        $token = isset($opts['protection_license_install_token']) ? trim((string) $opts['protection_license_install_token']) : '';
        if ($token !== '') return $token;
        if (defined('DS_LICENSE_INSTALL_TOKEN') && is_string(DS_LICENSE_INSTALL_TOKEN) && trim(DS_LICENSE_INSTALL_TOKEN) !== '') {
            return trim((string) DS_LICENSE_INSTALL_TOKEN);
        }
        $fileToken = self::read_install_token_from_file();
        if ($fileToken !== '') return $fileToken;
        return '';
    }

    public static function remote_license_bootstrap_install($opts = null) {
        $opts = is_array($opts) ? $opts : Settings::get();
        $api_url = isset($opts['protection_license_api_url']) ? trim((string) $opts['protection_license_api_url']) : '';
        $install_token = self::resolve_install_token($opts);
        if ($api_url === '') {
            return new \WP_Error('ds_bootstrap_remote_disabled', __('Remote license bootstrap is not configured.', 'ds'));
        }
        if ($install_token === '') {
            return new \WP_Error('ds_bootstrap_install_missing_token', __('Install token is missing for automatic license initialization.', 'ds'));
        }
        $payload = [
            'install_token' => $install_token,
            'site_url' => home_url('/'),
            'domain' => self::site_domain(),
            'instance_id' => self::instance_id(),
            'timestamp' => time(),
        ];
        return self::remote_post_json(self::endpoint_url_bootstrap_install($api_url), $payload, '');
    }

    public static function remote_license_bootstrap_legacy($opts = null) {
        $opts = is_array($opts) ? $opts : Settings::get();
        $api_url = isset($opts['protection_license_api_url']) ? trim((string) $opts['protection_license_api_url']) : '';
        $api_token = isset($opts['protection_license_bootstrap_token']) ? trim((string) $opts['protection_license_bootstrap_token']) : '';
        if ($api_url === '' || $api_token === '') {
            return new \WP_Error('ds_bootstrap_remote_disabled', __('Remote license bootstrap is not configured.', 'ds'));
        }
        $payload = [
            'site_url' => home_url('/'),
            'domain' => self::site_domain(),
            'instance_id' => self::instance_id(),
            'timestamp' => time(),
        ];
        return self::remote_post_json(self::endpoint_url_bootstrap($api_url), $payload, $api_token);
    }

    private static function persist_bootstrap_credentials($boot) {
        $key = isset($boot['license_key']) ? trim((string) $boot['license_key']) : '';
        if ($key === '') {
            return new \WP_Error('ds_bootstrap_missing_key', __('Bootstrap endpoint did not return license key.', 'ds'));
        }
        $all = get_option(Settings::OPTION_KEY, []);
        if (!is_array($all)) $all = [];
        if (!empty($boot['service_token'])) {
            $all['protection_license_api_token'] = sanitize_text_field((string) $boot['service_token']);
        }
        $all['protection_license_key'] = $key;
        update_option(Settings::OPTION_KEY, $all, false);
        $boot['license_key'] = $key;
        return $boot;
    }

    public static function ensure_bootstrap_license_key($opts = null) {
        $opts = is_array($opts) ? $opts : Settings::get();
        $current_key = isset($opts['protection_license_key']) ? trim((string) $opts['protection_license_key']) : '';
        if ($current_key !== '') {
            return ['license_key' => $current_key, 'created' => 0];
        }
        $install_boot = self::remote_license_bootstrap_install($opts);
        if (!is_wp_error($install_boot) && is_array($install_boot)) {
            $saved = self::persist_bootstrap_credentials($install_boot);
            if (is_wp_error($saved)) return $saved;
            $saved['bootstrap_mode'] = 'install_token';
            return $saved;
        }

        $legacy_token = isset($opts['protection_license_bootstrap_token']) ? trim((string) $opts['protection_license_bootstrap_token']) : '';
        if ($legacy_token !== '') {
            $legacy_boot = self::remote_license_bootstrap_legacy($opts);
            if (is_wp_error($legacy_boot) || !is_array($legacy_boot)) {
                return $legacy_boot;
            }
            $saved = self::persist_bootstrap_credentials($legacy_boot);
            if (is_wp_error($saved)) return $saved;
            $saved['bootstrap_mode'] = 'legacy_token';
            return $saved;
        }

        if (is_wp_error($install_boot)) {
            return $install_boot;
        }
        return new \WP_Error('ds_bootstrap_install_missing_token', __('Install token is missing for automatic license initialization.', 'ds'));
    }

    public static function ensure_site_credentials($opts = null) {
        $opts = is_array($opts) ? $opts : Settings::get();
        $api_url = isset($opts['protection_license_api_url']) ? trim((string) $opts['protection_license_api_url']) : '';
        $api_token = isset($opts['protection_license_api_token']) ? trim((string) $opts['protection_license_api_token']) : '';
        $license_key = isset($opts['protection_license_key']) ? trim((string) $opts['protection_license_key']) : '';
        if ($api_url === '') {
            return new \WP_Error('ds_creds_missing_url', __('License API URL is not configured.', 'ds'));
        }
        if ($api_token !== '' && $license_key !== '') {
            return ['api_url' => $api_url, 'api_token' => $api_token, 'license_key' => $license_key];
        }
        $boot = self::ensure_bootstrap_license_key($opts);
        if (is_wp_error($boot) || !is_array($boot)) return $boot;
        $all = Settings::get();
        return [
            'api_url' => isset($all['protection_license_api_url']) ? trim((string) $all['protection_license_api_url']) : '',
            'api_token' => isset($all['protection_license_api_token']) ? trim((string) $all['protection_license_api_token']) : '',
            'license_key' => isset($all['protection_license_key']) ? trim((string) $all['protection_license_key']) : '',
        ];
    }
}
