<?php

namespace RecastPaywall;

/**
 * Main plugin class
 */
class Plugin {
    /**
     * Plugin instance
     */
    private static ?Plugin $instance = null;

    /**
     * Plugin components
     */
    private Admin\Settings $settings;
    private Frontend\ContentGating $contentGating;
    private Frontend\BlockGating $blockGating;
    private Frontend\PaywallRenderer $paywallRenderer;
    private Api\RecastClient $recastClient;
    private Sync\InventorySync $inventorySync;
    private Blocks\PaywallBlock $paywallBlock;
    private Services\EntitlementService $entitlementService;
    private Rest\ApiController $apiController;

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

    /**
     * Constructor
     */
    private function __construct() {
        $this->initComponents();
        $this->initHooks();
    }

    /**
     * Initialize plugin components
     */
    private function initComponents(): void {
        $this->settings = new Admin\Settings();
        $this->recastClient = new Api\RecastClient();
        $this->entitlementService = new Services\EntitlementService($this->recastClient);
        $this->inventorySync = new Sync\InventorySync($this->recastClient);
        $this->paywallRenderer = new Frontend\PaywallRenderer($this->entitlementService);
        $this->contentGating = new Frontend\ContentGating($this->entitlementService);
        $this->blockGating = new Frontend\BlockGating($this->entitlementService, $this->paywallRenderer);
        $this->paywallBlock = new Blocks\PaywallBlock($this->entitlementService, $this->contentGating);
        $this->apiController = new Rest\ApiController($this->entitlementService, $this->inventorySync);
    }

    /**
     * Initialize WordPress hooks
     */
    private function initHooks(): void {
        // Text domain loading is handled automatically by WordPress for plugins hosted on WordPress.org
        // Register post meta
        add_action('init', [$this, 'registerPostMeta']);

        // Register Gutenberg block
        add_action('init', [$this->paywallBlock, 'registerBlock']);

        // Initialize REST API
        add_action('rest_api_init', [$this->apiController, 'registerRoutes']);

        // Initialize admin hooks
        if (is_admin()) {
            add_action('admin_init', [$this->settings, 'init']);
            add_action('admin_menu', [$this->settings, 'addMenuPage']);
            add_action('add_meta_boxes', [$this, 'addMetaBoxes']);
            add_action('enqueue_block_editor_assets', [$this, 'enqueueBlockEditorAssets']);
        }

        // Initialize frontend hooks
        if (!is_admin()) {
            add_action('wp_enqueue_scripts', [$this, 'enqueueFrontendAssets']);
            $this->contentGating->init();
            $this->blockGating->init();
        }

        // Add Recast importmap
        add_action('wp_head', function () {
            $map = [
                'imports' => [
                    'jose' => RECAST_PAYWALL_PLUGIN_URL . 'assets/js/vendor/jose.js',
                    '@recast-sdk/recast-jwt' => RECAST_PAYWALL_PLUGIN_URL . 'assets/js/vendor/recast-jwt.js',
                    '@recast-sdk/recast-browser' => RECAST_PAYWALL_PLUGIN_URL . 'assets/js/vendor/recast-browser.js',
                ],
            ];
        
            if (function_exists('wp_print_inline_script_tag')) {
                // Make sure this prints before your module scripts
                wp_print_inline_script_tag(
                    wp_json_encode($map),
                    ['type' => 'importmap', 'id' => 'recast-importmap']
                );
            } else {
                // Fallback for older WP
                echo '<script type="importmap">' . wp_json_encode($map) . '</script>';
            }
        }, 1);

        add_action('wp_head', function () {
            if (function_exists('wp_print_inline_script_tag')) {
                wp_print_inline_script_tag(
                    "import { RecastBrowser } from '@recast-sdk/recast-browser'; window.RecastBrowser = RecastBrowser;",
                    ['type' => 'module', 'id' => 'recast-bootstrap']
                );
            }
        }, 2);

        // Save meta then sync
        add_action('save_post', [$this, 'saveMetaBox'], 5, 2);
        add_action('save_post', [$this->inventorySync, 'syncPost'], 10, 2);
        // After REST saves (Block Editor), sync with fresh values
        add_action('rest_after_insert_post', [$this->inventorySync, 'handleRestAfterInsert'], 10, 3);
        // Also hook into meta updates to catch when paywall is enabled  
        add_action('updated_postmeta', [$this, 'handleMetaUpdate'], 10, 4);
        add_action('transition_post_status', [$this->inventorySync, 'handleStatusTransition'], 10, 3);
        add_action('before_delete_post', [$this->inventorySync, 'handlePostDeletion']);

        // AJAX handlers
        add_action('wp_ajax_recast_sync_post', [$this, 'handleAjaxSync']);
        add_action('wp_ajax_recast_test_connection', [$this->recastClient, 'handleTestConnection']);
        add_action('wp_ajax_recast_get_full_content', [$this, 'handleGetFullContent']);
        add_action('wp_ajax_nopriv_recast_get_full_content', [$this, 'handleGetFullContent']);

        // Webhook handler
        add_action('init', [$this, 'handleWebhooks']);

        // Scheduled cleanup of old transients
        add_action('recast_paywall_cleanup_transients', [$this->entitlementService, 'cleanupOldTransients']);
        if (!wp_next_scheduled('recast_paywall_cleanup_transients')) {
            wp_schedule_event(time(), 'daily', 'recast_paywall_cleanup_transients');
        }

        // Delayed sync for meta updates
        add_action('recast_paywall_delayed_sync', [$this, 'handleDelayedSync']);

        // WP-CLI commands
        if (defined('WP_CLI') && WP_CLI) {
            add_action('cli_init', [$this, 'registerCliCommands']);
        }
    }


    /**
     * Add meta boxes for Classic Editor
     */
    public function addMetaBoxes(): void {
        $postTypes = apply_filters('recast_paywall_post_types', ['post']);
        
        foreach ($postTypes as $postType) {
            // Only register legacy meta box for Classic Editor.
            if (function_exists('use_block_editor_for_post_type') && use_block_editor_for_post_type($postType)) {
                continue;
            }

            add_meta_box(
                'recast-paywall-meta',
                __('Recast Paywall', 'recast-paywall'),
                [$this, 'renderMetaBox'],
                $postType,
                'side',
                'high'
            );
        }
        
        // Enqueue meta box assets
        $this->enqueueMetaBoxAssets();
    }
    
    /**
     * Enqueue meta box assets
     */
    private function enqueueMetaBoxAssets(): void {
        wp_enqueue_style(
            'recast-paywall-meta-box',
            RECAST_PAYWALL_PLUGIN_URL . 'assets/css/meta-box.css',
            [],
            RECAST_PAYWALL_VERSION
        );
        
        wp_enqueue_script(
            'recast-paywall-meta-box',
            RECAST_PAYWALL_PLUGIN_URL . 'assets/js/meta-box.js',
            ['jquery'],
            RECAST_PAYWALL_VERSION,
            true
        );
        
        wp_localize_script('recast-paywall-meta-box', 'recastMetaBox', [
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'errorMessage' => __('Sync failed. Please try again.', 'recast-paywall'),
        ]);
    }

    /**
     * Render meta box content
     */
    public function renderMetaBox(\WP_Post $post): void {
        wp_nonce_field('recast_paywall_meta', 'recast_paywall_nonce');
        
        $itemId = get_post_meta($post->ID, '_recast_inventory_item_id', true);
        $lastSynced = get_post_meta($post->ID, '_recast_last_synced_at', true);
        $isPaywalled = get_post_meta($post->ID, '_recast_paywall_enabled', true);
        $price = get_post_meta($post->ID, '_recast_price', true);
        $status = get_post_meta($post->ID, '_recast_status', true);
        $geoAvailability = get_post_meta($post->ID, '_recast_geo_availability', true);
        $affiliateSharePct = get_post_meta($post->ID, '_recast_affiliate_share_pct', true);
        
        include RECAST_PAYWALL_PLUGIN_DIR . 'templates/meta-box.php';
    }

    /**
     * AJAX handler wrapper to ensure capability and nonce are checked and we force sync
     */
    public function handleAjaxSync(): void {
        if (!current_user_can('edit_posts')) {
            wp_die(esc_html__('Unauthorized', 'recast-paywall'));
        }

        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'] ?? '')), 'recast_sync_post')) {
            wp_die(esc_html__('Invalid nonce', 'recast-paywall'));
        }

        $postId = intval($_POST['post_id'] ?? 0);
        if (!$postId) {
            wp_send_json_error(['message' => __('Invalid post ID', 'recast-paywall')]);
        }

        // Force sync regardless of paywall flag
        $syncResult = $this->inventorySync->forceSyncPost($postId);

        if (!$syncResult) {
            // Check if API credentials are configured
            $settings = $this->settings->getSettings();
            $errorMessage = __('Sync failed. ', 'recast-paywall');
            
            
            if (empty($settings['api_key']) || empty($settings['api_secret'])) {
                $errorMessage .= __('Please configure your Recast API credentials in the plugin settings.', 'recast-paywall');
            } else {
                $errorMessage .= __('Please check your Recast API settings and try again.', 'recast-paywall');
            }
            
            wp_send_json_error([
                'message' => $errorMessage,
                'item_id' => get_post_meta($postId, '_recast_inventory_item_id', true),
                'last_synced' => get_post_meta($postId, '_recast_last_synced_at', true),
            ]);
        }

        wp_send_json_success([
            'message' => __('Post synced successfully', 'recast-paywall'),
            'item_id' => get_post_meta($postId, '_recast_inventory_item_id', true),
            'last_synced' => get_post_meta($postId, '_recast_last_synced_at', true),
        ]);
    }



    /**
     * Register post meta used by the plugin
     */
    public function registerPostMeta(): void {
        $args_public = [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'string',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'sanitize_callback' => function($value, $key, $object_type) {
                return sanitize_text_field($value);
            },
        ];

        register_post_meta('', '_recast_paywall_enabled', [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'boolean',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'default' => false,
        ]);
        register_post_meta('', '_recast_inventory_item_id', $args_public);
        register_post_meta('', '_recast_last_synced_at', $args_public);

        // Optional fields for product creation
        register_post_meta('', '_recast_price', [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'number',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'sanitize_callback' => function($value, $key, $object_type) {
                return absint($value);
            },
            'default' => 0,
        ]);
        register_post_meta('', '_recast_status', [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'string',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'sanitize_callback' => function($value, $key, $object_type) {
                return sanitize_text_field($value);
            },
            'default' => '',
        ]);
        register_post_meta('', '_recast_geo_availability', [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'string',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'sanitize_callback' => function($value, $key, $object_type) {
                return sanitize_text_field($value);
            },
            'default' => '',
        ]);
        register_post_meta('', '_recast_affiliate_share_pct', [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'number',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'sanitize_callback' => function($value, $key, $object_type) {
                return floatval($value);
            },
            'default' => 0,
        ]);
        // Gating mode: 'post' or 'block'
        register_post_meta('', '_recast_gating_mode', [
            'show_in_rest' => true,
            'single' => true,
            'type' => 'string',
            'auth_callback' => function() { return current_user_can('edit_posts'); },
            'sanitize_callback' => function($value) {
                return in_array($value, ['post','block'], true) ? $value : 'post';
            },
            'default' => 'post',
        ]);
    }

    

    /**
     * Handle delayed sync
     */
    public function handleDelayedSync(int $postId): void {
        $this->inventorySync->forceSyncPost($postId);
    }

    /**
     * Handle meta updates to trigger sync when paywall is enabled
     */
    public function handleMetaUpdate(int $metaId, int $postId, string $metaKey, $metaValue): void {
        // Only trigger on paywall-related meta changes
        if (!in_array($metaKey, ['_recast_paywall_enabled', '_recast_gating_mode', '_recast_price', '_recast_status', '_recast_geo_availability', '_recast_affiliate_share_pct'], true)) {
            return;
        }

        // Skip if this is a REST request (handled by rest_after_insert_post)
        if (defined('REST_REQUEST') && REST_REQUEST) {
            return;
        }

        $post = get_post($postId);
        if (!$post) {
            return;
        }

        // Only sync posts in editable statuses (allow draft, future, pending, private, publish)
        if (!$this->inventorySync->isStatusSyncable($post->post_status)) {
            return;
        }

        // Check if this change should trigger a sync
        if ($this->inventorySync->shouldSyncPost($postId)) {
            // Schedule sync for next request to avoid issues with current transaction
            wp_schedule_single_event(time() + 1, 'recast_paywall_delayed_sync', [$postId]);
        }
    }

    /**
     * Save meta from Classic Editor meta box
     */
    public function saveMetaBox(int $postId, \WP_Post $post): void {
        if (!isset($_POST['recast_paywall_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['recast_paywall_nonce'])), 'recast_paywall_meta')) {
            return;
        }
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }
        if (!current_user_can('edit_post', $postId)) {
            return;
        }

        $isPaywalled = !empty($_POST['_recast_paywall_enabled']);
        update_post_meta($postId, '_recast_paywall_enabled', $isPaywalled);

        $price = isset($_POST['_recast_price']) ? intval(wp_unslash($_POST['_recast_price'])) : '';
        $status = isset($_POST['_recast_status']) ? sanitize_text_field(wp_unslash($_POST['_recast_status'])) : '';
        $geo = isset($_POST['_recast_geo_availability']) ? sanitize_text_field(wp_unslash($_POST['_recast_geo_availability'])) : '';
        $aff = isset($_POST['_recast_affiliate_share_pct']) ? floatval(wp_unslash($_POST['_recast_affiliate_share_pct'])) : '';
        $mode = isset($_POST['_recast_gating_mode']) ? sanitize_text_field(wp_unslash($_POST['_recast_gating_mode'])) : '';

        if ($price !== '' && $price > 0) update_post_meta($postId, '_recast_price', $price); else delete_post_meta($postId, '_recast_price');
        if ($status !== '') update_post_meta($postId, '_recast_status', $status); else delete_post_meta($postId, '_recast_status');
        if ($geo !== '') update_post_meta($postId, '_recast_geo_availability', $geo); else delete_post_meta($postId, '_recast_geo_availability');
        if ($aff !== '') update_post_meta($postId, '_recast_affiliate_share_pct', $aff); else delete_post_meta($postId, '_recast_affiliate_share_pct');
        if ($mode !== '') update_post_meta($postId, '_recast_gating_mode', in_array($mode, ['post','block'], true) ? $mode : 'post');
    }

    /**
     * Enqueue block editor assets
     */
    public function enqueueBlockEditorAssets(): void {
        // Register the Paywall Section block
        wp_enqueue_script(
            'recast-paywall-block',
            RECAST_PAYWALL_PLUGIN_URL . 'assets/js/paywall-block.js',
            ['wp-blocks', 'wp-element', 'wp-block-editor', 'wp-i18n'],
            RECAST_PAYWALL_VERSION,
            true
        );

        // Existing per-block UI enhancements (toolbar toggles)
        wp_enqueue_script(
            'recast-paywall-block-editor',
            RECAST_PAYWALL_PLUGIN_URL . 'assets/js/block-editor.js',
            ['wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n', 'recast-paywall-block'],
            RECAST_PAYWALL_VERSION,
            true
        );

        wp_localize_script('recast-paywall-block-editor', 'recastPaywallBlock', [
            'nonce' => wp_create_nonce('recast_paywall_block'),
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'iconUrl' => RECAST_PAYWALL_PLUGIN_URL . 'assets/images/recast-logo.png',
            'strings' => [
                'paywallSection' => __('Recast Paywall Section', 'recast-paywall'),
                'paywallDescription' => __('Content within this block will be gated behind the paywall.', 'recast-paywall'),
                'syncNow' => __('Sync Now', 'recast-paywall'),
                'syncing' => __('Syncing...', 'recast-paywall'),
                'syncSuccess' => __('Synced successfully!', 'recast-paywall'),
                'syncError' => __('Sync failed. Please try again.', 'recast-paywall'),
            ]
        ]);

        // Gutenberg sidebar meta panel built via @wordpress/scripts
        $asset_path = RECAST_PAYWALL_PLUGIN_DIR . 'build/index.asset.php';
        if (file_exists($asset_path)) {
            $asset = include $asset_path;
            wp_enqueue_script(
                'recast-paywall-meta-panel',
                RECAST_PAYWALL_PLUGIN_URL . 'build/index.js',
                $asset['dependencies'] ?? ['wp-plugins','wp-edit-post','wp-components','wp-element','wp-data','wp-core-data','wp-i18n'],
                $asset['version'] ?? RECAST_PAYWALL_VERSION,
                true
            );

            // Provide icon URL and other config to the editor bundle
            wp_localize_script('recast-paywall-meta-panel', 'recastPaywallMeta', [
                'iconUrl' => RECAST_PAYWALL_PLUGIN_URL . 'assets/images/recast-logo.png',
            ]);

            if (file_exists(RECAST_PAYWALL_PLUGIN_DIR . 'build/index.css')) {
                wp_enqueue_style(
                    'recast-paywall-meta-panel',
                    RECAST_PAYWALL_PLUGIN_URL . 'build/index.css',
                    ['wp-components'],
                    $asset['version'] ?? RECAST_PAYWALL_VERSION
                );
            }
        }
    }

    /**
     * Enqueue frontend assets
     */
    public function enqueueFrontendAssets(): void {
        if (!is_singular()) {
            return;
        }

        // Enqueue paywall styles
        wp_enqueue_style(
            'recast-paywall-styles',
            RECAST_PAYWALL_PLUGIN_URL . 'assets/css/paywall.css',
            [],
            RECAST_PAYWALL_VERSION
        );

        // wp_enqueue_script(
        //     'recast-browser',
        //     'https://cdn.recast.com/browser.js',
        //     [],
        //     null,
        //     true
        // );

        wp_enqueue_script(
            'recast-paywall-frontend',
            RECAST_PAYWALL_PLUGIN_URL . 'assets/js/frontend.js',
            ['jquery'],
            RECAST_PAYWALL_VERSION,
            true
        );

        $settings = $this->settings->getSettings();
        
        wp_localize_script('recast-paywall-frontend', 'recastPaywall', [
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'restUrl' => rest_url('recast-paywall/v1/'),
            'nonce' => wp_create_nonce('wp_rest'),
            'brandId' => $settings['brand_id'] ?? '',
            'sandbox' => (bool) ($settings['sandbox'] ?? false),
            'postId' => get_the_ID(),
            'strings' => [
                'loading' => __('Loading...', 'recast-paywall'),
                'error' => __('An error occurred. Please try again.', 'recast-paywall'),
            ]
        ]);
    }

    /**
     * Handle webhook requests
     */
    public function handleWebhooks(): void {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Webhook requests from external services don't use WordPress nonces. Security is handled via signature verification in the WebhookHandler.
        if (!isset($_GET['recast_webhook'])) {
            return;
        }

        $webhookHandler = new Services\WebhookHandler($this->entitlementService);
        $webhookHandler->handle();
        exit;
    }

    /**
     * Handle AJAX request for full content
     */
    public function handleGetFullContent(): void {
        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'] ?? '')), 'wp_rest')) {
            wp_die(esc_html__('Invalid nonce', 'recast-paywall'));
        }

        $postId = intval($_POST['post_id'] ?? 0);
        
        if (!$postId) {
            wp_send_json_error(['message' => __('Invalid post ID', 'recast-paywall')]);
        }

        // Check if user is entitled
        $userId = get_current_user_id();
        if (!$this->entitlementService->isEntitled($postId, $userId)) {
            wp_send_json_error(['message' => __('Not entitled', 'recast-paywall')]);
        }

        $post = get_post($postId);
        
        if (!$post) {
            wp_send_json_error(['message' => __('Post not found', 'recast-paywall')]);
        }

        $content = apply_filters('the_content', $post->post_content);
        
        wp_send_json_success([
            'content' => $content,
        ]);
    }

    /**
     * Register WP-CLI commands
     */
    public function registerCliCommands(): void {
        \WP_CLI::add_command('recast', \RecastPaywall\CLI\Commands::class);
    }

    /**
     * Plugin activation
     */
    public static function activate(): void {
        // Set default options
        $defaultSettings = [
            'api_key' => '',
            'api_secret' => '',
            'brand_id' => '',
            'sandbox' => true,
            'summary_length' => 100,
            'show_teaser_to_search_engines' => false,
            'archive_on_delete' => true,
        ];

        add_option('recast_paywall_settings', $defaultSettings);

        // Flush rewrite rules for REST API
        flush_rewrite_rules();
    }

    /**
     * Plugin deactivation
     */
    public static function deactivate(): void {
        // Clear scheduled events
        wp_clear_scheduled_hook('recast_paywall_sync_retry');
        
        // Flush rewrite rules
        flush_rewrite_rules();
    }
}
