<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™ -- NUCLEAR+++
// File: /includes/class-product-catalog.php
// Description: Nightly WooCommerce product sync, catalog storage, and priority queue management - NUCLEAR+++
// Last Edited: 2026-05-15
// ==================================================

namespace AutoMarketerAI;

defined('ABSPATH') || exit;

final class ProductCatalog
{
    private const CRON_HOOK  = 'amai_product_catalog_sync';
    private const CRON_SCHED = 'daily';
    private const SYNC_TIME  = '02:30:00'; // 2:30am UTC, after DB backup

    // ------------------------------------------------------------------
    // Boot
    // ------------------------------------------------------------------
    public static function init(): void
    {
        add_action(self::CRON_HOOK, [self::class, 'sync']);
        add_action('wp',            [self::class, 'maybeSchedule']);
        register_deactivation_hook(AMAI_PLUGIN_DIR . 'automarketer-ai.php', [self::class, 'clearSchedule']);
    }

    // ------------------------------------------------------------------
    // Schedule the nightly sync if not already scheduled
    // ------------------------------------------------------------------
    public static function maybeSchedule(): void
    {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            $today = gmdate('Y-m-d') . ' ' . self::SYNC_TIME;
            $ts    = strtotime($today . ' UTC');
            if ($ts === false) {
                $ts = time();
            }
            if ($ts < time()) {
                $ts += DAY_IN_SECONDS;
            }
            wp_schedule_event($ts, self::CRON_SCHED, self::CRON_HOOK);
        }
    }

    // ------------------------------------------------------------------
    // Clear scheduled event on deactivation
    // ------------------------------------------------------------------
    public static function clearSchedule(): void
    {
        $ts = wp_next_scheduled(self::CRON_HOOK);
        if ($ts) {
            wp_unschedule_event($ts, self::CRON_HOOK);
        }
    }

    // ------------------------------------------------------------------
    // Run the nightly sync -- WooCommerce only
    // ------------------------------------------------------------------
    public static function sync(): void
    {
        $active_modules = (array) get_option('amai_active_modules', []);
        if (!in_array('store-woocommerce', $active_modules, true)) {
            return;
        }

        if (!class_exists('WooCommerce') || !function_exists('wc_get_products')) {
            return;
        }

        global $wpdb;
        $table    = $wpdb->prefix . 'amai_product_catalog';
        $provider = 'store-woocommerce';
        $now      = gmdate('Y-m-d H:i:s');

        // Collect external IDs already in catalog
        $existing_ids = $wpdb->get_col(
            $wpdb->prepare(
                "SELECT external_id FROM {$table} WHERE provider_id = %s",
                $provider
            )
        );
        $existing_ids = is_array($existing_ids) ? array_flip($existing_ids) : [];
        $seen_ids     = [];
        $total        = 0;
        $page         = 1;
        $limit        = 100;

        while (true) {
            $wc_products = wc_get_products([
                'status'  => 'publish',
                'limit'   => $limit,
                'page'    => $page,
                'orderby' => 'date',
                'order'   => 'DESC',
            ]);

            if (empty($wc_products)) {
                break;
            }

            foreach ($wc_products as $product) {
                if (!($product instanceof \WC_Product)) {
                    continue;
                }

                $external_id = (string) $product->get_id();
                $seen_ids[]  = $external_id;
                $is_new      = !isset($existing_ids[$external_id]) ? 1 : 0;

                $price      = $product->get_regular_price() !== '' ? number_format((float) $product->get_regular_price(), 2, '.', '') : null;
                $sale_price = $product->get_sale_price()    !== '' ? number_format((float) $product->get_sale_price(),    2, '.', '') : null;
                $on_sale    = $product->is_on_sale() ? 1 : 0;
                $currency   = strtoupper(get_woocommerce_currency());

                $image_id  = $product->get_image_id();
                $image_url = $image_id ? (string) wp_get_attachment_url((int) $image_id) : '';

                $stock = null;
                if ($product->managing_stock()) {
                    $stock = (int) $product->get_stock_quantity();
                }

                $description = wp_strip_all_tags($product->get_description() ?: $product->get_short_description());
                $created_raw = $product->get_date_created() ? $product->get_date_created()->format('Y-m-d H:i:s') : $now;

                $wpdb->query(
                    $wpdb->prepare(
                        "INSERT INTO {$table}
                            (provider_id, external_id, name, description, price, currency,
                             image_url, product_url, on_sale, sale_price, stock, is_new, created_at, synced_at)
                         VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %d, %s, %s, %d, %s, %s)
                         ON DUPLICATE KEY UPDATE
                            name        = VALUES(name),
                            description = VALUES(description),
                            price       = VALUES(price),
                            currency    = VALUES(currency),
                            image_url   = VALUES(image_url),
                            product_url = VALUES(product_url),
                            on_sale     = VALUES(on_sale),
                            sale_price  = VALUES(sale_price),
                            stock       = VALUES(stock),
                            is_new      = IF(is_new = 0 AND VALUES(is_new) = 1, 1, is_new),
                            synced_at   = VALUES(synced_at)",
                        $provider,
                        $external_id,
                        substr($product->get_name(), 0, 500),
                        $description,
                        $price,
                        substr($currency, 0, 8),
                        $image_url,
                        (string) $product->get_permalink(),
                        $on_sale,
                        $sale_price,
                        $stock,
                        $is_new,
                        $created_raw,
                        $now
                    )
                );

                $total++;
            }

            if (count($wc_products) < $limit) {
                break;
            }

            $page++;
        }

        // Remove products that no longer exist in WooCommerce
        if (!empty($seen_ids)) {
            $placeholders = implode(',', array_fill(0, count($seen_ids), '%s'));
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM {$table} WHERE provider_id = %s AND external_id NOT IN ({$placeholders})",
                    array_merge([$provider], $seen_ids)
                )
            );
        }

        $health = $total > 0 ? 'ok' : 'empty';
        update_option('amai_store_catalog_health', $health, false);
        update_option('amai_store_catalog_count',  $total,  false);
        update_option('amai_store_last_synced',    $now,    false);

        $wpdb->query(
            "UPDATE {$wpdb->prefix}amai_product_queue SET last_synced_at = '{$now}' WHERE id = 1"
        );
    }

    // ------------------------------------------------------------------
    // Pick the next product to feature based on priority queue rules:
    //
    // Priority 1 -- sale products, pattern: sale / regular / sale
    // Priority 2 -- new products (added since last sync), oldest-new first
    // Priority 3 -- regular rotation, newest to oldest, saves position
    // Wrap-around -- when regular list exhausted, restart from newest
    // ------------------------------------------------------------------
    public static function nextProduct(): ?array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_product_catalog';
        $queue = $wpdb->prefix . 'amai_product_queue';

        $state = $wpdb->get_row("SELECT * FROM {$queue} WHERE id = 1", ARRAY_A);
        if (!is_array($state)) {
            return null;
        }

        $sale_catalog_id  = (int)    ($state['sale_catalog_id']  ?? 0);
        $sale_phase       = (string) ($state['sale_phase']       ?? '');
        $sale_phase_index = (int)    ($state['sale_phase_index'] ?? 0);

        // -- Priority 1: sale products with sale/regular/sale pattern --
        $sale_products = $wpdb->get_results(
            "SELECT * FROM {$table} WHERE on_sale = 1 ORDER BY created_at DESC",
            ARRAY_A
        );

        if (!empty($sale_products)) {
            $current_sale = null;
            foreach ($sale_products as $sp) {
                if ((int) ($sp['id'] ?? 0) === $sale_catalog_id) {
                    $current_sale = $sp;
                    break;
                }
            }

            if ($current_sale === null) {
                $current_sale     = $sale_products[0];
                $sale_phase       = 'sale';
                $sale_phase_index = 0;
            }

            if ($sale_phase === '' || $sale_phase === 'sale') {
                $product = self::normalizeRow($current_sale);
                $product['_post_angle'] = 'sale';

                if ($sale_phase_index === 0) {
                    self::updateQueueState($queue, [
                        'sale_catalog_id'  => (int) $current_sale['id'],
                        'sale_phase'       => 'regular',
                        'sale_phase_index' => 1,
                    ]);
                } else {
                    $next_sale = self::nextSaleProduct($sale_products, (int) $current_sale['id']);
                    self::updateQueueState($queue, [
                        'sale_catalog_id'  => $next_sale !== null ? (int) $next_sale['id'] : 0,
                        'sale_phase'       => 'sale',
                        'sale_phase_index' => 0,
                    ]);
                }

                return $product;
            }

            if ($sale_phase === 'regular') {
                $product = self::normalizeRow($current_sale);
                $product['_post_angle'] = 'regular';

                self::updateQueueState($queue, [
                    'sale_catalog_id'  => (int) $current_sale['id'],
                    'sale_phase'       => 'sale',
                    'sale_phase_index' => 1,
                ]);

                return $product;
            }
        } else {
            if ($sale_catalog_id !== 0 || $sale_phase !== '') {
                self::updateQueueState($queue, [
                    'sale_catalog_id'  => 0,
                    'sale_phase'       => '',
                    'sale_phase_index' => 0,
                ]);
            }
        }

        // -- Priority 2: new products (is_new = 1), oldest first --
        $new_product = $wpdb->get_row(
            "SELECT * FROM {$table} WHERE is_new = 1 ORDER BY created_at ASC LIMIT 1",
            ARRAY_A
        );

        if ($new_product !== null) {
            $wpdb->query(
                $wpdb->prepare(
                    "UPDATE {$table} SET is_new = 0 WHERE id = %d",
                    (int) $new_product['id']
                )
            );

            $product = self::normalizeRow($new_product);
            $product['_post_angle'] = 'new';
            return $product;
        }

        // -- Priority 3: regular rotation, newest to oldest, saved position --
        $last_catalog_id = (int) ($state['last_catalog_id'] ?? 0);

        $regular_products = $wpdb->get_results(
            "SELECT * FROM {$table} WHERE on_sale = 0 AND is_new = 0 ORDER BY created_at DESC",
            ARRAY_A
        );

        if (empty($regular_products)) {
            $regular_products = $wpdb->get_results(
                "SELECT * FROM {$table} ORDER BY created_at DESC",
                ARRAY_A
            );
        }

        if (empty($regular_products)) {
            return null;
        }

        $index = 0;
        if ($last_catalog_id !== 0) {
            foreach ($regular_products as $i => $rp) {
                if ((int) ($rp['id'] ?? 0) === $last_catalog_id) {
                    $index = $i + 1;
                    break;
                }
            }
        }

        if ($index >= count($regular_products)) {
            $index = 0;
        }

        $chosen = $regular_products[$index];

        self::updateQueueState($queue, [
            'last_catalog_id' => (int) $chosen['id'],
            'queue_position'  => $index,
        ]);

        $product = self::normalizeRow($chosen);
        $product['_post_angle'] = 'regular';
        return $product;
    }

    // ------------------------------------------------------------------
    // Returns true if WooCommerce store provider is active and connected
    // ------------------------------------------------------------------
    public static function isConnected(): bool
    {
        $active_modules = (array) get_option('amai_active_modules', []);
        return in_array('store-woocommerce', $active_modules, true) && class_exists('WooCommerce');
    }

    // ------------------------------------------------------------------
    // Returns total product count in the local catalog
    // ------------------------------------------------------------------
    public static function getCount(): int
    {
        global $wpdb;
        $count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}amai_product_catalog");
        return (int) $count;
    }

    // ------------------------------------------------------------------
    // Returns catalog health status: 'ok', 'empty', or 'never_synced'
    // ------------------------------------------------------------------
    public static function getHealth(): string
    {
        $health = (string) get_option('amai_store_catalog_health', '');
        return $health !== '' ? $health : 'never_synced';
    }

    // ------------------------------------------------------------------
    // Normalize a DB row to the standard product array shape
    // ------------------------------------------------------------------
    private static function normalizeRow(array $row): array
    {
        return [
            'id'          => (string) ($row['external_id'] ?? ''),
            'name'        => (string) ($row['name']        ?? ''),
            'description' => (string) ($row['description'] ?? ''),
            'price'       => isset($row['price'])      && $row['price']      !== null ? (float) $row['price']      : null,
            'currency'    => (string) ($row['currency'] ?? 'USD'),
            'image_url'   => (string) ($row['image_url']   ?? ''),
            'url'         => (string) ($row['product_url'] ?? ''),
            'on_sale'     => (bool)   ($row['on_sale']     ?? false),
            'sale_price'  => isset($row['sale_price']) && $row['sale_price'] !== null ? (float) $row['sale_price'] : null,
            'stock'       => isset($row['stock'])      && $row['stock']      !== null ? (int)   $row['stock']      : null,
            'is_new'      => (bool)   ($row['is_new']      ?? false),
            'created_at'  => (string) ($row['created_at']  ?? ''),
            '_catalog_id' => (int)    ($row['id']           ?? 0),
        ];
    }

    // ------------------------------------------------------------------
    // Advance to the next sale product after $current_id
    // ------------------------------------------------------------------
    private static function nextSaleProduct(array $sale_products, int $current_id): ?array
    {
        $count = count($sale_products);
        if ($count <= 1) {
            return null;
        }

        foreach ($sale_products as $i => $sp) {
            if ((int) ($sp['id'] ?? 0) === $current_id) {
                return $sale_products[($i + 1) % $count];
            }
        }

        return $sale_products[0];
    }

    // ------------------------------------------------------------------
    // Update specific queue state fields
    // ------------------------------------------------------------------
    private static function updateQueueState(string $queue_table, array $fields): void
    {
        global $wpdb;

        $set_parts = [];
        $values    = [];

        if (isset($fields['sale_catalog_id'])) {
            $set_parts[] = 'sale_catalog_id = %d';
            $values[]    = $fields['sale_catalog_id'];
        }
        if (isset($fields['sale_phase'])) {
            $set_parts[] = 'sale_phase = %s';
            $values[]    = $fields['sale_phase'];
        }
        if (isset($fields['sale_phase_index'])) {
            $set_parts[] = 'sale_phase_index = %d';
            $values[]    = $fields['sale_phase_index'];
        }
        if (isset($fields['last_catalog_id'])) {
            $set_parts[] = 'last_catalog_id = %d';
            $values[]    = $fields['last_catalog_id'];
        }
        if (isset($fields['queue_position'])) {
            $set_parts[] = 'queue_position = %d';
            $values[]    = $fields['queue_position'];
        }

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

        $values[] = 1;
        $wpdb->query(
            $wpdb->prepare(
                'UPDATE ' . $queue_table . ' SET ' . implode(', ', $set_parts) . ' WHERE id = %d',
                $values
            )
        );
    }
}