<?php
/**
 * CastConductor Update Checker
 *
 * Checks for available plugin updates via the CastConductor API.
 * Shows admin notice when updates are available (no auto-update).
 *
 * @package CastConductor
 * @since 5.4.0
 */

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

/**
 * Class CastConductor_Update_Checker
 *
 * Manages update checking and admin notifications for plugin updates.
 * Updates are manual only - no automatic installation.
 */
class CastConductor_Update_Checker {

    /**
     * API endpoint for version checks
     */
    const VERSION_CHECK_URL = 'https://api.castconductor.com/api/plugin/version-check';

    /**
     * Option keys
     */
    const OPTION_UPDATE_DATA = 'castconductor_update_data';
    const OPTION_LAST_CHECK = 'castconductor_update_last_check';
    const OPTION_DISMISSED_VERSION = 'castconductor_update_dismissed';

    /**
     * Cache duration (12 hours)
     */
    const CACHE_DURATION = 43200;

    /**
     * Cron hook name
     */
    const CRON_HOOK = 'castconductor_update_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 twice-daily update check
        add_action('init', array($this, 'schedule_update_check'));
        
        // Hook for the scheduled check
        add_action(self::CRON_HOOK, array($this, 'check_for_updates'));
        
        // Admin notices for available updates
        add_action('admin_notices', array($this, 'display_update_notice'));
        
        // Check on admin load if cache expired
        add_action('admin_init', array($this, 'maybe_check_for_updates'));
        
        // AJAX handlers
        add_action('wp_ajax_castconductor_dismiss_update', array($this, 'ajax_dismiss_update'));
        add_action('wp_ajax_castconductor_check_update', array($this, 'ajax_check_update'));
        
        // Add update info to plugins page
        add_filter('plugins_api', array($this, 'plugin_info'), 20, 3);
        add_filter('site_transient_update_plugins', array($this, 'push_update_info'));
    }

    /**
     * Schedule twice-daily update check if not already scheduled
     */
    public function schedule_update_check() {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            // Random offset to distribute load
            $random_offset = rand(0, 3600);
            wp_schedule_event(time() + $random_offset, 'twicedaily', self::CRON_HOOK);
        }
    }

    /**
     * Clear scheduled events (called on deactivation)
     */
    public static function clear_scheduled_events() {
        $timestamp = wp_next_scheduled(self::CRON_HOOK);
        if ($timestamp) {
            wp_unschedule_event($timestamp, self::CRON_HOOK);
        }
    }

    /**
     * Check if we should run an update check on this page load
     */
    public function maybe_check_for_updates() {
        // Only on CastConductor admin pages or plugins page
        $screen = get_current_screen();
        if (!$screen) {
            return;
        }
        
        $should_check = (
            strpos($screen->id, 'castconductor') !== false ||
            $screen->id === 'plugins' ||
            $screen->id === 'update-core'
        );
        
        if (!$should_check) {
            return;
        }
        
        // Check if cache is expired
        $last_check = get_option(self::OPTION_LAST_CHECK, 0);
        if (time() - $last_check > self::CACHE_DURATION) {
            $this->check_for_updates();
        }
    }

    /**
     * Check for updates from the API
     *
     * @return array|WP_Error Update data or error
     */
    public function check_for_updates() {
        $current_version = defined('CASTCONDUCTOR_VERSION') ? CASTCONDUCTOR_VERSION : '5.0.0';
        $license_key = get_option('castconductor_license_key', '');
        
        // Build request URL
        $url = add_query_arg(array(
            'version' => $current_version,
            'license_key' => $license_key,
            'domain' => home_url(),
            'wp_version' => get_bloginfo('version'),
            'php_version' => PHP_VERSION,
        ), self::VERSION_CHECK_URL);
        
        // Make the request
        $response = wp_remote_get($url, array(
            'timeout' => 15,
            'headers' => array(
                'Accept' => 'application/json',
            ),
        ));
        
        if (is_wp_error($response)) {
            error_log('CastConductor Update Check Error: ' . $response->get_error_message());
            return $response;
        }
        
        $code = wp_remote_retrieve_response_code($response);
        if ($code !== 200) {
            error_log('CastConductor Update Check HTTP Error: ' . $code);
            return new WP_Error('http_error', 'HTTP Error: ' . $code);
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        
        if (!$data || !isset($data['success'])) {
            error_log('CastConductor Update Check: Invalid response');
            return new WP_Error('invalid_response', 'Invalid API response');
        }
        
        // Store the update data
        update_option(self::OPTION_UPDATE_DATA, $data);
        update_option(self::OPTION_LAST_CHECK, time());
        
        return $data;
    }

    /**
     * Get cached update data
     *
     * @return array|null
     */
    public function get_update_data() {
        return get_option(self::OPTION_UPDATE_DATA, null);
    }

    /**
     * Check if an update is available
     *
     * @return bool
     */
    public function is_update_available() {
        $data = $this->get_update_data();
        return $data && !empty($data['update_available']);
    }

    /**
     * Display admin notice for available updates
     */
    public function display_update_notice() {
        // Only show to admins
        if (!current_user_can('manage_options')) {
            return;
        }
        
        // Check if update is available
        $data = $this->get_update_data();
        if (!$data || empty($data['update_available'])) {
            return;
        }
        
        $latest_version = $data['latest_version'] ?? '';
        
        // Check if this version was dismissed
        $dismissed = get_option(self::OPTION_DISMISSED_VERSION, '');
        if ($dismissed === $latest_version) {
            return;
        }
        
        // Check compatibility
        $requirements = $data['requirements'] ?? array();
        $compatible = ($requirements['php_compatible'] ?? true) && ($requirements['wp_compatible'] ?? true);
        
        $download_url = $data['download_url'] ?? 'https://castconductor.com/downloads/castconductor-plugin.zip';
        $changelog = $data['changelog'] ?? array();
        $requires_roku_rebuild = !empty($data['requires_roku_rebuild']);
        $roku_rebuild_reason = $data['roku_rebuild_reason'] ?? '';
        
        ?>
        <div class="notice notice-info is-dismissible castconductor-update-notice" 
             data-version="<?php echo esc_attr($latest_version); ?>">
            <p>
                <strong>🎉 CastConductor Update Available!</strong>
                <?php if (!$compatible): ?>
                    <span class="dashicons dashicons-warning" style="color: #f0ad4e;"></span>
                <?php endif; ?>
            </p>
            <p>
                Version <strong><?php echo esc_html($latest_version); ?></strong> is now available.
                You are running version <strong><?php echo esc_html(CASTCONDUCTOR_VERSION); ?></strong>.
            </p>
            <?php if ($requires_roku_rebuild): ?>
                <p style="color: #856404; background: #fff3cd; padding: 10px 14px; border-radius: 4px; border-left: 4px solid #ffc107;">
                    <strong>⚠️ Roku App Rebuild Required</strong><br>
                    <?php if ($roku_rebuild_reason): ?>
                        <?php echo esc_html($roku_rebuild_reason); ?><br>
                    <?php endif; ?>
                    After updating the plugin, you'll need to rebuild your Roku app using the Toaster.
                </p>
            <?php endif; ?>
            <?php if (!empty($changelog)): ?>
                <details style="margin: 10px 0;">
                    <summary style="cursor: pointer; font-weight: 600;">What's New</summary>
                    <ul style="margin-top: 10px; list-style: disc; margin-left: 20px;">
                        <?php foreach ($changelog as $item): ?>
                            <li><?php echo esc_html($item); ?></li>
                        <?php endforeach; ?>
                    </ul>
                </details>
            <?php endif; ?>
            <?php if (!$compatible): ?>
                <p style="color: #856404; background: #fff3cd; padding: 8px 12px; border-radius: 4px;">
                    <strong>Note:</strong> This update may require 
                    <?php if (!($requirements['php_compatible'] ?? true)): ?>
                        PHP <?php echo esc_html($requirements['min_php'] ?? '7.4'); ?>+
                    <?php endif; ?>
                    <?php if (!($requirements['wp_compatible'] ?? true)): ?>
                        WordPress <?php echo esc_html($requirements['min_wp'] ?? '6.0'); ?>+
                    <?php endif; ?>
                </p>
            <?php endif; ?>
            <p>
                <a href="<?php echo esc_url($download_url); ?>" 
                   class="button button-primary" 
                   target="_blank">
                    Download Update
                </a>
                <a href="<?php echo esc_url($data['changelog_url'] ?? '#'); ?>" 
                   class="button" 
                   target="_blank">
                    View Changelog
                </a>
                <button type="button" 
                        class="button castconductor-dismiss-update" 
                        data-version="<?php echo esc_attr($latest_version); ?>">
                    Remind Me Later
                </button>
                <button type="button" 
                        class="button castconductor-refresh-update" 
                        style="margin-left: 10px;">
                    <span class="dashicons dashicons-update" style="vertical-align: middle;"></span> Check for Updates
                </button>
            </p>
        </div>
        <script>
        jQuery(function($) {
            // Handle dismiss button
            $('.castconductor-dismiss-update').on('click', function(e) {
                e.preventDefault();
                var version = $(this).data('version');
                $.post(ajaxurl, {
                    action: 'castconductor_dismiss_update',
                    version: version,
                    _wpnonce: '<?php echo wp_create_nonce('castconductor_dismiss_update'); ?>'
                });
                $(this).closest('.notice').fadeOut();
            });
            
            // Also handle the X dismiss button
            $(document).on('click', '.castconductor-update-notice .notice-dismiss', function() {
                var version = $(this).closest('.notice').data('version');
                $.post(ajaxurl, {
                    action: 'castconductor_dismiss_update',
                    version: version,
                    _wpnonce: '<?php echo wp_create_nonce('castconductor_dismiss_update'); ?>'
                });
            });
            
            // Handle refresh/check for updates button
            $('.castconductor-refresh-update').on('click', function(e) {
                e.preventDefault();
                var $btn = $(this);
                $btn.prop('disabled', true).find('.dashicons').addClass('spin');
                $.post(ajaxurl, {
                    action: 'castconductor_check_update',
                    _wpnonce: '<?php echo wp_create_nonce('castconductor_check_update'); ?>'
                }, function(response) {
                    location.reload();
                }).fail(function() {
                    $btn.prop('disabled', false).find('.dashicons').removeClass('spin');
                    alert('Failed to check for updates. Please try again.');
                });
            });
        });
        </script>
        <style>
        .castconductor-refresh-update .dashicons.spin {
            animation: cc-spin 1s linear infinite;
        }
        @keyframes cc-spin {
            100% { transform: rotate(360deg); }
        }
        </style>
        <?php
    }

    /**
     * AJAX handler to dismiss update notice
     */
    public function ajax_dismiss_update() {
        check_ajax_referer('castconductor_dismiss_update');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }
        
        $version = sanitize_text_field($_POST['version'] ?? '');
        if ($version) {
            update_option(self::OPTION_DISMISSED_VERSION, $version);
        }
        
        wp_send_json_success();
    }

    /**
     * AJAX handler to manually check for updates
     */
    public function ajax_check_update() {
        check_ajax_referer('castconductor_check_update');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Permission denied');
        }
        
        // Clear dismissed version to show notice again
        delete_option(self::OPTION_DISMISSED_VERSION);
        
        $result = $this->check_for_updates();
        
        if (is_wp_error($result)) {
            wp_send_json_error($result->get_error_message());
        }
        
        wp_send_json_success($result);
    }

    /**
     * Filter the plugins API to show our update info
     *
     * @param false|object|array $result The result object or array
     * @param string $action The API action
     * @param object $args API arguments
     * @return false|object|array
     */
    public function plugin_info($result, $action, $args) {
        if ($action !== 'plugin_information') {
            return $result;
        }
        
        if (!isset($args->slug) || $args->slug !== 'castconductor-v5') {
            return $result;
        }
        
        $data = $this->get_update_data();
        if (!$data) {
            return $result;
        }
        
        $info = new stdClass();
        $info->name = 'CastConductor';
        $info->slug = 'castconductor-v5';
        $info->version = $data['latest_version'] ?? CASTCONDUCTOR_VERSION;
        $info->author = '<a href="https://castconductor.com">CastConductor</a>';
        $info->homepage = 'https://castconductor.com';
        $info->requires = $data['requirements']['min_wp'] ?? '6.0';
        $info->requires_php = $data['requirements']['min_php'] ?? '7.4';
        $info->tested = $data['requirements']['tested_wp'] ?? '6.7';
        $info->downloaded = 0;
        $info->last_updated = $data['release_date'] ?? '';
        $info->sections = array(
            'description' => 'CastConductor is a powerful broadcast management plugin for WordPress.',
            'changelog' => $this->format_changelog($data['changelog'] ?? array()),
        );
        $info->download_link = $data['download_url'] ?? '';
        $info->banners = array(
            'high' => 'https://castconductor.com/wp-content/uploads/plugin-banner-1544x500.png',
            'low' => 'https://castconductor.com/wp-content/uploads/plugin-banner-772x250.png',
        );
        
        return $info;
    }

    /**
     * Format changelog array as HTML
     *
     * @param array $changelog
     * @return string
     */
    private function format_changelog($changelog) {
        if (empty($changelog)) {
            return '<p>No changelog available.</p>';
        }
        
        $html = '<ul>';
        foreach ($changelog as $item) {
            $html .= '<li>' . esc_html($item) . '</li>';
        }
        $html .= '</ul>';
        
        return $html;
    }

    /**
     * Push update info to WordPress update transient
     *
     * @param object $transient
     * @return object
     */
    public function push_update_info($transient) {
        if (empty($transient->checked)) {
            return $transient;
        }
        
        $data = $this->get_update_data();
        if (!$data || empty($data['update_available'])) {
            return $transient;
        }
        
        $plugin_file = 'castconductor-v5/castconductor.php';
        
        // Only add if not already in response (we don't want to override WP.org)
        if (!isset($transient->response[$plugin_file])) {
            $item = new stdClass();
            $item->slug = 'castconductor-v5';
            $item->plugin = $plugin_file;
            $item->new_version = $data['latest_version'] ?? '';
            $item->url = 'https://castconductor.com';
            $item->package = $data['download_url'] ?? ''; // Enable one-click install from Plugins page
            $item->icons = array(
                '1x' => 'https://castconductor.com/wp-content/uploads/plugin-icon-128x128.png',
                '2x' => 'https://castconductor.com/wp-content/uploads/plugin-icon-256x256.png',
            );
            $item->banners = array(
                'low' => 'https://castconductor.com/wp-content/uploads/plugin-banner-772x250.png',
                'high' => 'https://castconductor.com/wp-content/uploads/plugin-banner-1544x500.png',
            );
            $item->requires = $data['requirements']['min_wp'] ?? '6.0';
            $item->requires_php = $data['requirements']['min_php'] ?? '7.4';
            $item->tested = $data['requirements']['tested_wp'] ?? '6.7';
            
            $transient->response[$plugin_file] = $item;
        }
        
        return $transient;
    }
}

// Initialize
CastConductor_Update_Checker::instance();
