<?php
/**
 * CastConductor License Manager
 *
 * Handles license validation via phone home to the CastConductor Provisioning API.
 * Performs daily license checks and manages license status.
 *
 * @package CastConductor
 * @since 5.4.0
 */

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

/**
 * Class CastConductor_License_Manager
 *
 * Manages license validation by periodically checking with the CastConductor
 * Provisioning API at api.castconductor.com
 */
class CastConductor_License_Manager {

    /**
     * Provisioning API base URL
     */
    const API_BASE_URL = 'https://api.castconductor.com';

    /**
     * Option keys
     */
    const OPTION_LICENSE_KEY = 'castconductor_license_key';
    const OPTION_LICENSE_STATUS = 'castconductor_license_status';
    const OPTION_LICENSE_DATA = 'castconductor_license_data';
    const OPTION_LAST_CHECK = 'castconductor_license_last_check';

    /**
     * Transient for caching license status
     */
    const CACHE_TRANSIENT = 'castconductor_license_cache';
    const CACHE_DURATION = DAY_IN_SECONDS; // 24 hours

    /**
     * Cron hook name
     */
    const CRON_HOOK = 'castconductor_daily_license_check';

    /**
     * Single instance
     */
    private static $instance = null;

    /**
     * Get singleton instance
     */
    public static function instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor
     */
    private function __construct() {
        // Schedule daily license check
        add_action('init', array($this, 'schedule_daily_check'));
        
        // Hook for the scheduled check
        add_action(self::CRON_HOOK, array($this, 'do_license_check'));
        
        // Admin notices for license status
        add_action('admin_notices', array($this, 'display_license_notices'));
        
        // Check on plugin load if cache expired (failsafe)
        add_action('admin_init', array($this, 'maybe_check_license'));
        
        // Add settings page section
        add_action('castconductor_settings_license_section', array($this, 'render_license_settings'));
        
        // AJAX handler for manual license validation
        add_action('wp_ajax_castconductor_validate_license', array($this, 'ajax_validate_license'));
    }

    /**
     * Schedule daily license check if not already scheduled
     */
    public function schedule_daily_check() {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            // Schedule for a random time to distribute load
            $random_offset = rand(0, 43200); // Random offset up to 12 hours
            wp_schedule_event(time() + $random_offset, 'daily', self::CRON_HOOK);
        }
    }

    /**
     * Clear scheduled events (called on deactivation)
     */
    public static function clear_scheduled_events() {
        wp_clear_scheduled_hook(self::CRON_HOOK);
    }

    /**
     * Check if we should verify license (cache expired)
     */
    public function maybe_check_license() {
        // Only run in admin
        if (!is_admin()) {
            return;
        }

        // Check if we have a license key
        $license_key = get_option(self::OPTION_LICENSE_KEY, '');
        if (empty($license_key)) {
            return;
        }

        // Check if cache is still valid
        $cached = get_transient(self::CACHE_TRANSIENT);
        if ($cached !== false) {
            return; // Cache still valid
        }

        // Cache expired, do a check
        $this->do_license_check();
    }

    /**
     * Perform license check against Provisioning API
     *
     * @param bool $force Force check even if cached
     * @return array|WP_Error License data or error
     */
    public function do_license_check($force = false) {
        $license_key = get_option(self::OPTION_LICENSE_KEY, '');
        
        if (empty($license_key)) {
            return new WP_Error('no_license', __('No license key configured', 'castconductor'));
        }

        // Check cache unless forced
        if (!$force) {
            $cached = get_transient(self::CACHE_TRANSIENT);
            if ($cached !== false) {
                return $cached;
            }
        }

        // Build request URL
        $url = add_query_arg(array(
            'key'     => $license_key,
            'domain'  => $this->get_site_domain(),
            'version' => CASTCONDUCTOR_VERSION,
        ), self::API_BASE_URL . '/api/license/check');

        // Make request
        $response = wp_remote_get($url, array(
            'timeout'   => 15,
            'sslverify' => true,
            'headers'   => array(
                'Accept' => 'application/json',
            ),
        ));

        // Handle request errors
        if (is_wp_error($response)) {
            $this->log_check('error', $response->get_error_message());
            
            // On network error, keep existing status but don't update cache
            // This prevents license from appearing invalid during network issues
            return $response;
        }

        $status_code = wp_remote_retrieve_response_code($response);
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);

        // Update stored data
        update_option(self::OPTION_LAST_CHECK, current_time('mysql'));

        if ($status_code === 200 && isset($data['valid']) && $data['valid'] === true) {
            // License is valid
            $license_data = array(
                'valid'                => true,
                'plan'                 => $data['plan'] ?? 'basic',
                'status'               => $data['status'] ?? 'active',
                'expires_at'           => $data['expires_at'] ?? null,
                'trial_ends_at'        => $data['trial_ends_at'] ?? null,
                'trial_days_remaining' => $data['trial_days_remaining'] ?? null,
                'features'             => $data['features'] ?? array(),
                'message'              => $data['message'] ?? '',
                'checked_at'           => current_time('mysql'),
            );

            update_option(self::OPTION_LICENSE_STATUS, $license_data['status']);
            update_option(self::OPTION_LICENSE_DATA, $license_data);
            set_transient(self::CACHE_TRANSIENT, $license_data, self::CACHE_DURATION);

            $this->log_check('success', $license_data['status']);

            return $license_data;

        } else {
            // License is invalid or error
            $error_message = $data['error'] ?? __('Unknown error', 'castconductor');
            $status = $data['status'] ?? 'invalid';

            $license_data = array(
                'valid'      => false,
                'status'     => $status,
                'error'      => $error_message,
                'checked_at' => current_time('mysql'),
            );

            update_option(self::OPTION_LICENSE_STATUS, $status);
            update_option(self::OPTION_LICENSE_DATA, $license_data);
            set_transient(self::CACHE_TRANSIENT, $license_data, self::CACHE_DURATION);

            $this->log_check('invalid', $error_message);

            return $license_data;
        }
    }

    /**
     * Get the site domain (without protocol)
     *
     * @return string
     */
    private function get_site_domain() {
        $url = home_url();
        $parsed = wp_parse_url($url);
        return $parsed['host'] ?? $url;
    }

    /**
     * Log license check (for debugging)
     *
     * @param string $result Check result
     * @param string $details Additional details
     */
    private function log_check($result, $details) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log(sprintf(
                'CastConductor License Check: %s - %s (Domain: %s)',
                $result,
                $details,
                $this->get_site_domain()
            ));
        }
    }

    /**
     * Display admin notices for license status
     */
    public function display_license_notices() {
        // Only show on CastConductor pages
        $screen = get_current_screen();
        if (!$screen || strpos($screen->id, 'castconductor') === false) {
            return;
        }

        $license_key = get_option(self::OPTION_LICENSE_KEY, '');
        $license_data = get_option(self::OPTION_LICENSE_DATA, array());

        // No license configured
        if (empty($license_key)) {
            ?>
            <div class="notice notice-warning is-dismissible">
                <p>
                    <strong><?php esc_html_e('CastConductor License Required', 'castconductor'); ?></strong>
                    <?php esc_html_e('Please enter your license key to enable all features and receive updates.', 'castconductor'); ?>
                    <a href="<?php echo esc_url(admin_url('admin.php?page=castconductor-settings#license')); ?>">
                        <?php esc_html_e('Enter License Key', 'castconductor'); ?>
                    </a>
                </p>
            </div>
            <?php
            return;
        }

        // License invalid or expired
        if (!empty($license_data) && (!isset($license_data['valid']) || $license_data['valid'] === false)) {
            $status = $license_data['status'] ?? 'invalid';
            $message = $license_data['error'] ?? __('Your license is not valid.', 'castconductor');

            $class = 'notice-error';
            if ($status === 'expired') {
                $message = __('Your CastConductor license has expired. Please renew to continue receiving updates and support.', 'castconductor');
            } elseif ($status === 'revoked' || $status === 'cancelled') {
                $message = __('Your CastConductor license has been cancelled. Contact support if you believe this is an error.', 'castconductor');
            }

            ?>
            <div class="notice <?php echo esc_attr($class); ?>">
                <p>
                    <strong><?php esc_html_e('CastConductor License Issue', 'castconductor'); ?></strong>
                    <?php echo esc_html($message); ?>
                </p>
            </div>
            <?php
            return;
        }

        // Grace period warning
        if (!empty($license_data) && isset($license_data['status']) && $license_data['status'] === 'grace_period') {
            ?>
            <div class="notice notice-warning">
                <p>
                    <strong><?php esc_html_e('CastConductor License Grace Period', 'castconductor'); ?></strong>
                    <?php esc_html_e('Your license is in a grace period. Please renew soon to avoid service interruption.', 'castconductor'); ?>
                    <?php if (!empty($license_data['expires_at'])): ?>
                        <?php 
                        printf(
                            esc_html__('Grace period ends: %s', 'castconductor'),
                            esc_html(date_i18n(get_option('date_format'), strtotime($license_data['expires_at'])))
                        );
                        ?>
                    <?php endif; ?>
                </p>
            </div>
            <?php
            return;
        }

        // Trial period notice
        if (!empty($license_data) && isset($license_data['status']) && $license_data['status'] === 'trial') {
            $trial_days = isset($license_data['trial_days_remaining']) ? intval($license_data['trial_days_remaining']) : null;
            
            if ($trial_days !== null && $trial_days > 0) {
                // Active trial
                $notice_class = $trial_days <= 3 ? 'notice-warning' : 'notice-info';
                ?>
                <div class="notice <?php echo esc_attr($notice_class); ?> is-dismissible">
                    <p>
                        <strong>
                            <?php 
                            printf(
                                esc_html__('🎉 Trial: %d day%s remaining', 'castconductor'),
                                $trial_days,
                                $trial_days !== 1 ? 's' : ''
                            );
                            ?>
                        </strong>
                        —
                        <?php esc_html_e('After the trial ends, your Roku app will continue to work and all content remains unchanged. A CastConductor watermark will appear on your channel until you subscribe.', 'castconductor'); ?>
                        <a href="https://castconductor.com/pricing/" target="_blank">
                            <?php esc_html_e('View Plans →', 'castconductor'); ?>
                        </a>
                    </p>
                </div>
                <?php
            } elseif ($trial_days === 0) {
                // Trial expired
                ?>
                <div class="notice notice-warning">
                    <p>
                        <strong><?php esc_html_e('⏰ Trial Expired', 'castconductor'); ?></strong>
                        —
                        <?php esc_html_e('Your Roku app is still working, but a CastConductor watermark is now visible to viewers. Subscribe to remove the watermark and unlock all features.', 'castconductor'); ?>
                        <a href="https://castconductor.com/pricing/" target="_blank" class="button button-primary" style="margin-left: 10px;">
                            <?php esc_html_e('Subscribe Now', 'castconductor'); ?>
                        </a>
                    </p>
                </div>
                <?php
            }
        }
    }

    /**
     * Get current license status
     *
     * @return array License status data
     */
    public function get_license_status() {
        $license_data = get_option(self::OPTION_LICENSE_DATA, array());
        
        if (empty($license_data)) {
            return array(
                'valid'  => false,
                'status' => 'unconfigured',
            );
        }

        return $license_data;
    }

    /**
     * Check if license is valid
     *
     * @return bool
     */
    public function is_license_valid() {
        $status = $this->get_license_status();
        return isset($status['valid']) && $status['valid'] === true;
    }

    /**
     * Check if we should show watermark (grace period or expired)
     *
     * @return bool
     */
    public function should_show_watermark() {
        $status = $this->get_license_status();
        
        // Show watermark if not valid
        if (!$this->is_license_valid()) {
            return true;
        }

        // Show watermark during grace period
        if (isset($status['features']['watermark']) && $status['features']['watermark']) {
            return true;
        }

        // Show watermark if in grace period status
        if (isset($status['status']) && $status['status'] === 'grace_period') {
            return true;
        }

        return false;
    }

    /**
     * Get license features
     *
     * @return array Features array
     */
    public function get_features() {
        $status = $this->get_license_status();
        return $status['features'] ?? array();
    }

    /**
     * Get license plan
     *
     * @return string Plan name
     */
    public function get_plan() {
        $status = $this->get_license_status();
        return $status['plan'] ?? 'none';
    }

    /**
     * Save license key (with immediate validation)
     *
     * @param string $license_key The license key to save
     * @return array|WP_Error Validation result
     */
    public function save_license_key($license_key) {
        $license_key = strtoupper(sanitize_text_field($license_key));
        
        // Save the key
        update_option(self::OPTION_LICENSE_KEY, $license_key);
        
        // Clear cache to force fresh check
        delete_transient(self::CACHE_TRANSIENT);
        
        // Validate immediately
        return $this->do_license_check(true);
    }

    /**
     * Remove license key
     */
    public function remove_license_key() {
        delete_option(self::OPTION_LICENSE_KEY);
        delete_option(self::OPTION_LICENSE_STATUS);
        delete_option(self::OPTION_LICENSE_DATA);
        delete_option(self::OPTION_LAST_CHECK);
        delete_transient(self::CACHE_TRANSIENT);
    }

    /**
     * AJAX handler for manual license validation
     */
    public function ajax_validate_license() {
        check_ajax_referer('castconductor_license_nonce', 'nonce');

        if (!current_user_can('manage_options')) {
            wp_send_json_error(array('message' => __('Permission denied', 'castconductor')));
        }

        $license_key = isset($_POST['license_key']) ? sanitize_text_field($_POST['license_key']) : '';

        if (empty($license_key)) {
            wp_send_json_error(array('message' => __('Please enter a license key', 'castconductor')));
        }

        $result = $this->save_license_key($license_key);

        if (is_wp_error($result)) {
            wp_send_json_error(array('message' => $result->get_error_message()));
        }

        if (isset($result['valid']) && $result['valid']) {
            wp_send_json_success(array(
                'message' => sprintf(
                    __('License validated! Plan: %s, Status: %s', 'castconductor'),
                    ucfirst($result['plan']),
                    ucfirst($result['status'])
                ),
                'data' => $result,
            ));
        } else {
            wp_send_json_error(array(
                'message' => $result['error'] ?? __('License validation failed', 'castconductor'),
            ));
        }
    }

    /**
     * Render license settings section
     */
    public function render_license_settings() {
        $license_key = get_option(self::OPTION_LICENSE_KEY, '');
        $license_data = $this->get_license_status();
        $last_check = get_option(self::OPTION_LAST_CHECK, '');
        ?>
        <div class="castconductor-license-section" id="license">
            <h2><?php esc_html_e('License', 'castconductor'); ?></h2>
            
            <table class="form-table">
                <tr>
                    <th scope="row">
                        <label for="castconductor_license_key"><?php esc_html_e('License Key', 'castconductor'); ?></label>
                    </th>
                    <td>
                        <input type="text" 
                               id="castconductor_license_key" 
                               name="castconductor_license_key" 
                               value="<?php echo esc_attr($license_key); ?>" 
                               class="regular-text"
                               placeholder="XXXX-XXXX-XXXX-XXXX"
                        />
                        <button type="button" 
                                id="castconductor_validate_license" 
                                class="button button-secondary">
                            <?php esc_html_e('Validate License', 'castconductor'); ?>
                        </button>
                        <p class="description">
                            <?php esc_html_e('Enter your CastConductor license key. Find this in your purchase confirmation email.', 'castconductor'); ?>
                        </p>
                    </td>
                </tr>
                
                <?php if (!empty($license_key)): ?>
                <tr>
                    <th scope="row"><?php esc_html_e('Status', 'castconductor'); ?></th>
                    <td>
                        <?php
                        $status_class = 'status-unknown';
                        $status_text = __('Unknown', 'castconductor');
                        
                        if (isset($license_data['valid'])) {
                            if ($license_data['valid']) {
                                $status_class = 'status-valid';
                                $status_text = sprintf(
                                    __('Valid - %s (%s)', 'castconductor'),
                                    ucfirst($license_data['plan'] ?? 'basic'),
                                    ucfirst($license_data['status'] ?? 'active')
                                );
                            } else {
                                $status_class = 'status-invalid';
                                $status_text = sprintf(
                                    __('Invalid - %s', 'castconductor'),
                                    $license_data['error'] ?? __('Unknown error', 'castconductor')
                                );
                            }
                        }
                        ?>
                        <span class="castconductor-license-status <?php echo esc_attr($status_class); ?>">
                            <?php echo esc_html($status_text); ?>
                        </span>
                        
                        <?php if (!empty($last_check)): ?>
                        <p class="description">
                            <?php 
                            printf(
                                esc_html__('Last checked: %s', 'castconductor'),
                                esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($last_check)))
                            );
                            ?>
                        </p>
                        <?php endif; ?>
                        
                        <?php 
                        // Show watermark warning ONLY if license has a problem
                        // A valid+active license should NEVER show this warning
                        $is_valid_active = isset($license_data['valid']) && $license_data['valid'] === true 
                            && isset($license_data['status']) && $license_data['status'] === 'active';
                        
                        if (!$is_valid_active):
                            // Check various watermark-triggering conditions
                            $show_watermark = isset($license_data['features']['watermark']) && $license_data['features']['watermark'];
                            $is_grace_period = isset($license_data['status']) && $license_data['status'] === 'grace_period';
                            $is_expired = isset($license_data['status']) && $license_data['status'] === 'expired';
                            // Trial expired only counts if license is still in 'trial' status (not converted to paid)
                            $is_trial_expired = isset($license_data['status']) && $license_data['status'] === 'trial'
                                && isset($license_data['trial_days_remaining']) && $license_data['trial_days_remaining'] === 0;
                            
                            if ($show_watermark || $is_grace_period || $is_expired || $is_trial_expired): ?>
                        <p class="description" style="color: #b32d2e; margin-top: 8px;">
                            <span class="dashicons dashicons-warning" style="color: #b32d2e;"></span>
                            <?php esc_html_e('CastConductor watermark is visible on your Roku channel. Subscribe or renew to remove it.', 'castconductor'); ?>
                        </p>
                            <?php endif; ?>
                        <?php endif; ?>
                    </td>
                </tr>
                <?php endif; ?>
            </table>
            
            <div id="castconductor_license_result"></div>
        </div>
        
        <style>
            .castconductor-license-status {
                display: inline-block;
                padding: 4px 12px;
                border-radius: 4px;
                font-weight: 600;
            }
            .castconductor-license-status.status-valid {
                background: #d4edda;
                color: #155724;
            }
            .castconductor-license-status.status-invalid {
                background: #f8d7da;
                color: #721c24;
            }
            .castconductor-license-status.status-unknown {
                background: #e2e3e5;
                color: #383d41;
            }
        </style>
        
        <script>
        jQuery(document).ready(function($) {
            $('#castconductor_validate_license').on('click', function() {
                var $button = $(this);
                var $result = $('#castconductor_license_result');
                var licenseKey = $('#castconductor_license_key').val();
                
                if (!licenseKey) {
                    $result.html('<div class="notice notice-error inline"><p><?php esc_html_e('Please enter a license key', 'castconductor'); ?></p></div>');
                    return;
                }
                
                $button.prop('disabled', true).text('<?php esc_html_e('Validating...', 'castconductor'); ?>');
                $result.html('');
                
                $.ajax({
                    url: ajaxurl,
                    type: 'POST',
                    data: {
                        action: 'castconductor_validate_license',
                        nonce: '<?php echo wp_create_nonce('castconductor_license_nonce'); ?>',
                        license_key: licenseKey
                    },
                    success: function(response) {
                        if (response.success) {
                            $result.html('<div class="notice notice-success inline"><p>' + response.data.message + '</p></div>');
                            location.reload(); // Reload to show updated status
                        } else {
                            $result.html('<div class="notice notice-error inline"><p>' + response.data.message + '</p></div>');
                        }
                    },
                    error: function() {
                        $result.html('<div class="notice notice-error inline"><p><?php esc_html_e('Connection error. Please try again.', 'castconductor'); ?></p></div>');
                    },
                    complete: function() {
                        $button.prop('disabled', false).text('<?php esc_html_e('Validate License', 'castconductor'); ?>');
                    }
                });
            });
        });
        </script>
        <?php
    }
}

// Initialize the license manager
function castconductor_license_manager() {
    return CastConductor_License_Manager::instance();
}
