<?php

/**
 * RetentionAnalytics Hooks
 *
 * Handles WooCommerce Analytics menu registration, asset enqueuing,
 * database migration, and backfill scheduling.
 *
 * @package ArraySubs\Features\RetentionAnalytics\Services
 * @since 1.9.0
 */

namespace ArraySubs\Features\RetentionAnalytics\Services;

defined('ABSPATH') || exit;

use ArraySubs\Features\RetentionAnalytics\Migrations\CreateRetentionLogsTable;
use ArraySubs\Supports\ActionScheduler;
use ArraySubs\Supports\Config;

/**
 * RetentionAnalytics hooks integration
 */
class Hooks
{
    /**
     * Retention analytics admin page slug.
     *
     * @var string
     */
    const PAGE_SLUG = 'arraysubs-retention-analytics';

    /**
     * Retention analytics wc-admin path.
     *
     * @var string
     */
    const PAGE_PATH = '/analytics/arraysubs-retention';

    /**
     * Enable auto-loading via AbstractLoader
     *
     * @var bool
     */
    public static $loadable = true;

    /**
     * DB version for the retention logs table
     *
     * @var string
     */
    const DB_VERSION = '1.0.0';

    /**
     * Constructor - Register hooks
     */
    public function __construct()
    {
        \add_action('init', [$this, 'maybeCreateTable'], 5);
        \add_filter('woocommerce_analytics_report_menu_items', [$this, 'addAnalyticsMenuItem']);
        \add_action('admin_enqueue_scripts', [$this, 'enqueueAssets']);

        // Backfill handler.
        \add_action(
            ActionScheduler::HOOK_BACKFILL_RETENTION_LOGS,
            [$this, 'handleBackfill'],
            10,
            1
        );

        // add class to body for retention analytics pages
        // adding it through js
        // \add_filter('admin_body_class', function ($body_class) {
        //     if ($this->isRetentionPage()) {
        //         $body_class .= ' arraysubs-retention-analytics-page-body';
        //     }
        //     return $body_class;
        // });
    }

    /**
     * Create the retention logs table if needed
     *
     * @return void
     */
    public function maybeCreateTable(): void
    {
        $current_version = \get_option('arraysubs_retention_logs_db_version', '0');

        if (\version_compare($current_version, self::DB_VERSION, '<')) {
            CreateRetentionLogsTable::up();
            \update_option('arraysubs_retention_logs_db_version', self::DB_VERSION);

            // Schedule backfill only on first creation.
            if ($current_version === '0') {
                $this->scheduleBackfill();
            }
        }
    }

    /**
     * Schedule a one-time backfill of historical cancelled subscriptions
     *
     * @return void
     */
    private function scheduleBackfill(): void
    {
        ActionScheduler::scheduleSingle(
            ActionScheduler::HOOK_BACKFILL_RETENTION_LOGS,
            time() + 30,
            [0],
            ActionScheduler::GROUP_MAINTENANCE
        );
    }

    /**
     * Backfill handler — processes 50 cancelled subscriptions per batch.
     *
     * @param int $offset Current offset.
     * @return void
     */
    public function handleBackfill(int $offset): void
    {
        if (!ActionScheduler::acquireLock(ActionScheduler::HOOK_BACKFILL_RETENTION_LOGS, [$offset])) {
            return;
        }

        try {
            $this->runBackfillBatch($offset);
        } finally {
            ActionScheduler::releaseLock(ActionScheduler::HOOK_BACKFILL_RETENTION_LOGS, [$offset]);
        }
    }

    /**
     * Execute a single backfill batch.
     *
     * @param int $offset Current offset.
     * @return void
     */
    private function runBackfillBatch(int $offset): void
    {
        global $wpdb;

        $batch_size = 50;
        $table      = CreateRetentionLogsTable::getTableName();

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $subscriptions = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT ID FROM {$wpdb->posts}
                 WHERE post_type = 'arraysubs_data'
                   AND post_status = 'arraysubs-cancelled'
                 ORDER BY ID ASC
                 LIMIT %d OFFSET %d",
                $batch_size,
                $offset
            )
        );

        if (empty($subscriptions)) {
            return;
        }

        foreach ($subscriptions as $row) {
            $sub_id = \absint($row->ID);

            // Skip if already logged.
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $exists = $wpdb->get_var(
                $wpdb->prepare(
                    'SELECT id FROM ' . \esc_sql($table) . ' WHERE subscription_id = %d AND event_type = %s LIMIT 1',
                    $sub_id,
                    'cancelled'
                )
            );

            if ($exists) {
                continue;
            }

            $subscription = \arraysubs_get_subscription($sub_id);
            if (!$subscription instanceof \WP_Post) {
                continue;
            }

            RetentionLogger::logFromMeta($subscription);
        }

        // Schedule next batch if we got a full page.
        if (count($subscriptions) >= $batch_size) {
            ActionScheduler::scheduleSingle(
                ActionScheduler::HOOK_BACKFILL_RETENTION_LOGS,
                time() + 10,
                [$offset + $batch_size],
                ActionScheduler::GROUP_MAINTENANCE
            );
        }
    }

    /**
     * Add the retention page to the WooCommerce Analytics menu.
     *
     * @param array $report_pages Existing analytics report pages.
     * @return array
     */
    public function addAnalyticsMenuItem(array $report_pages): array
    {
        $item = [
            'id'         => self::PAGE_SLUG,
            'title'      => \__('Retention', 'arraysubs'),
            'page_title' => \__('Retention', 'arraysubs'),
            'parent'     => 'woocommerce-analytics',
            'path'       => self::PAGE_PATH,
            'capability' => 'manage_woocommerce',
        ];

        $settings_index = null;

        foreach ($report_pages as $index => $report_page) {
            if (
                \is_array($report_page)
                && !empty($report_page['id'])
                && $report_page['id'] === 'woocommerce-analytics-orders'
            ) {
                $order_index = $index;
                break;
            }
        }

        if ($order_index === null) {
            $report_pages[] = $item;
            return $report_pages;
        }

        array_splice($report_pages, $order_index, 0, [$item]);

        return $report_pages;
    }

    /**
     * Enqueue assets on WooCommerce Analytics pages.
     *
     * Loaded on all analytics pages for SPA compatibility — the JS
     * observes route changes and mounts/unmounts the React app as needed.
     *
     * @param string $hook Current admin page hook.
     * @return void
     */
    public function enqueueAssets(string $hook): void
    {
        if (!$this->isAnalyticsPage()) {
            return;
        }

        $asset_file = Config::get('plugin.public_path') . 'build/admin/retention-analytics.asset.php';
        $asset      = \file_exists($asset_file)
            ? require $asset_file
            : ['dependencies' => ['wp-element', 'wp-i18n'], 'version' => ARRAYSUBS_VERSION];

        \wp_enqueue_style(
            'arraysubs-retention-analytics',
            Config::get('plugin.public_url') . 'build/admin/retention-analytics.css',
            [],
            $asset['version']
        );

        \wp_enqueue_script(
            'arraysubs-retention-analytics',
            Config::get('plugin.public_url') . 'build/admin/retention-analytics.js',
            $asset['dependencies'],
            $asset['version'],
            true
        );

        \wp_set_script_translations(
            'arraysubs-retention-analytics',
            'arraysubs',
            Config::get('plugin.plugin_path') . 'languages'
        );

        $json_flags  = JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT;
        $inline_data = [
            'nonce'        => \wp_create_nonce('wp_rest'),
            'apiBaseUrl'   => \esc_url_raw(\rest_url()),
            'currency'     => \get_woocommerce_currency_symbol(),
            'currencyCode' => \get_woocommerce_currency(),
            'dateFormat'   => \get_option('date_format') ?: 'Y-m-d',
            'pagePath'     => self::PAGE_PATH,
        ];

        \wp_add_inline_script(
            'arraysubs-retention-analytics',
            'window.arraySubsRetention = ' . \wp_json_encode($inline_data, $json_flags) . ';',
            'before'
        );
    }

    /**
     * Check if the current admin page is a WooCommerce Analytics page.
     *
     * @return bool
     */
    private function isAnalyticsPage(): bool
    {
        if (!\is_admin()) {
            return false;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page check.
        $page = isset($_GET['page']) ? \sanitize_text_field(\wp_unslash($_GET['page'])) : '';
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page check.
        $path = isset($_GET['path']) ? \sanitize_text_field(\wp_unslash($_GET['path'])) : '';

        return $page === 'wc-admin';
    }

    /**
     * Check if the current admin page is the WooCommerce Analytics Retention page
     *
     * @return bool
     */
    private function isRetentionPage(): bool
    {
        if (!$this->isAnalyticsPage()) {
            return false;
        }

        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only page check.
        $path = isset($_GET['path']) ? \sanitize_text_field(\wp_unslash($_GET['path'])) : '';

        return $path === self::PAGE_PATH;
    }
}
