<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™ -- NUCLEAR+++
// File: /includes/class-product-engine.php
// Description: Generates product promotion posts Mon/Wed/Fri from WooCommerce catalog - NUCLEAR+++
// Last Edited: 2026-05-15
// ==================================================

namespace AutoMarketerAI;

defined('ABSPATH') || exit;

final class ProductEngine
{
    private const CRON_HOOK  = 'amai_product_engine_run';
    private const CRON_SCHED = 'daily';

    // Per-channel prompt style for product promotion posts
    private const CHANNEL_STYLE = [
        'facebook'  => 'Write a Facebook post promoting this product for a business. Warm and conversational tone. 2-4 sentences. Focus on customer benefit. Include the product URL on its own line at the end if provided. No hashtags.',
        'instagram' => 'Write an Instagram caption promoting this product. Punchy opening, 3-4 benefit-focused lines. End with "Link in bio." and 5-7 relevant hashtags on a new line. No URL in the caption.',
        'x'         => 'Write a tweet promoting this product. Under 220 characters leaving room for a URL. Punchy and direct. 1-2 hashtags max.',
        'tiktok'    => 'Write a TikTok caption promoting this product. Hook-first, casual and energetic. 2-3 short lines. End with "Link in bio." and 3-5 hashtags.',
        'linkedin'  => 'Write a LinkedIn post promoting this product. Professional tone, lead with a customer insight or benefit. 3-4 sentences. End with the product URL on its own line.',
        'google'    => 'Write a Google Business Profile post promoting this product. Friendly and local-business tone. 2-3 sentences. Clear call to action. Include the product URL if provided.',
    ];

    // Seasonal context windows
    private const SEASONAL_WINDOWS = [
        ['label' => "Black Friday",    'month' => 11, 'day_start' => 20, 'day_end' => 30],
        ['label' => "Cyber Monday",    'month' => 11, 'day_start' => 25, 'day_end' => 30],
        ['label' => "Christmas",       'month' => 12, 'day_start' =>  1, 'day_end' => 25],
        ['label' => "New Year",        'month' => 12, 'day_start' => 26, 'day_end' => 31],
        ['label' => "Valentine's Day", 'month' =>  2, 'day_start' =>  1, 'day_end' => 14],
        ['label' => "Mother's Day",    'month' =>  5, 'day_start' =>  1, 'day_end' => 12],
        ['label' => "Father's Day",    'month' =>  6, 'day_start' =>  1, 'day_end' => 21],
        ['label' => "Back to School",  'month' =>  8, 'day_start' => 15, 'day_end' => 31],
        ['label' => "Halloween",       'month' => 10, 'day_start' => 15, 'day_end' => 31],
        ['label' => "Easter",          'month' =>  4, 'day_start' =>  1, 'day_end' => 20],
        ['label' => "Summer",          'month' =>  6, 'day_start' => 22, 'day_end' => 30],
        ['label' => "Summer",          'month' =>  7, 'day_start' =>  1, 'day_end' => 31],
    ];

    // Active social channels eligible for product posts
    private const CHANNEL_MAP = [
        'AutoMarketerAI\\FacebookAuth'     => 'facebook',
        'AutoMarketerAI\\InstagramChannel' => 'instagram',
        'AutoMarketerAI\\XAuth'            => 'x',
        'AutoMarketerAI\\TikTokAuth'       => 'tiktok',
        'AutoMarketerAI\\GoogleChannel'    => 'google',
        'AutoMarketerAI\\LinkedInChannel'  => 'linkedin',
    ];

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

    public static function addSchedule(array $schedules): array
    {
        if (!isset($schedules[self::CRON_SCHED])) {
            $schedules[self::CRON_SCHED] = [
                'interval' => DAY_IN_SECONDS,
                'display'  => 'Daily',
            ];
        }
        return $schedules;
    }

    public static function maybeSchedule(): void
    {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            $ts = self::nextWeekdayTimestamp();
            wp_schedule_event($ts, self::CRON_SCHED, self::CRON_HOOK);
        }
    }

    public static function clearSchedule(): void
    {
        $ts = wp_next_scheduled(self::CRON_HOOK);
        if ($ts) {
            wp_unschedule_event($ts, self::CRON_HOOK);
        }
    }

    // ------------------------------------------------------------------
    // Main cron handler -- runs daily, fires only Mon/Wed/Fri
    // ------------------------------------------------------------------
    public static function run(): void
    {
        $dow = (int) gmdate('N');
        if (!in_array($dow, [1, 3, 5], true)) {
            return;
        }

        $active_modules = (array) get_option('amai_active_modules', []);
        if (!in_array('store-integration', $active_modules, true)) {
            return;
        }

        if (!ProductCatalog::isConnected()) {
            return;
        }

        if (ProductCatalog::getCount() === 0) {
            return;
        }

        $ai = self::resolveAiProvider();
        if ($ai === null) {
            return;
        }

        $product = ProductCatalog::nextProduct();
        if ($product === null) {
            return;
        }

        $channels = self::getActiveConnectedChannels();
        if (empty($channels)) {
            return;
        }

        $angle  = (string) ($product['_post_angle'] ?? 'regular');
        $season = self::detectSeason();
        $batch  = 'product-' . gmdate('YmdHis') . '-' . substr(md5($product['id']), 0, 6);
        $date   = gmdate('Y-m-d');
        $status = (get_option('amai_approval_mode', 'review') === 'autopilot') ? 'approved' : 'draft';

        foreach ($channels as $channel) {
            $content = self::generatePost($ai, $product, $channel, $angle, $season);
            if ($content === '') {
                continue;
            }
            self::storePost($channel, $content, $status, $batch, $date);
        }
    }

    // ------------------------------------------------------------------
    // Generate promotional post copy for a single channel
    // ------------------------------------------------------------------
    private static function generatePost(
        array $ai,
        array $product,
        string $channel,
        string $angle,
        string $season
    ): string {
        $style         = self::CHANNEL_STYLE[$channel] ?? self::CHANNEL_STYLE['facebook'];
        $business_name = (string) get_option('amai_business_name', get_bloginfo('name'));

        $product_block = 'Product name: ' . ($product['name'] ?? '') . "\n";

        if (($product['description'] ?? '') !== '') {
            $product_block .= 'Product description: ' . $product['description'] . "\n";
        }

        if (($product['price'] ?? null) !== null) {
            $currency = strtoupper($product['currency'] ?? 'USD');
            if ($angle === 'sale' && ($product['sale_price'] ?? null) !== null) {
                $product_block .= 'Regular price: ' . $currency . ' ' . number_format((float) $product['price'], 2) . "\n";
                $product_block .= 'Sale price: ' . $currency . ' ' . number_format((float) $product['sale_price'], 2) . "\n";
            } else {
                $product_block .= 'Price: ' . $currency . ' ' . number_format((float) $product['price'], 2) . "\n";
            }
        }

        if (($product['url'] ?? '') !== '') {
            $product_block .= 'Product URL: ' . $product['url'] . "\n";
        }

        if (($product['stock'] ?? null) !== null && (int) $product['stock'] <= 5 && (int) $product['stock'] > 0) {
            $product_block .= 'Stock: Only ' . (int) $product['stock'] . ' left in stock.' . "\n";
        }

        $angle_instruction = '';
        if ($angle === 'sale') {
            $angle_instruction = 'This product is currently ON SALE. Emphasize the savings and create urgency without being pushy.' . "\n";
        } elseif ($angle === 'new') {
            $angle_instruction = 'This is a NEW product, just added to the store. Emphasize the freshness and newness.' . "\n";
        }

        $seasonal_instruction = '';
        if ($season !== '') {
            $seasonal_instruction = 'Seasonal context: ' . $season . ' is coming up. Naturally weave in seasonal relevance if it fits the product -- do not force it.' . "\n";
        }

        $variety_instructions = [
            'Focus on the key customer benefit this product delivers.',
            'Lead with a problem this product solves.',
            'Write from a lifestyle angle -- how this product fits into the customer\'s life.',
            'Open with a question that makes the reader think about whether they need this.',
            'Lead with social proof framing -- something like "Customers love..." or "One of our most popular...".',
        ];
        $variety = $variety_instructions[((int) gmdate('W') + (int) gmdate('j')) % count($variety_instructions)];

        $prompt = $style . "\n\n"
            . 'Business: ' . $business_name . "\n"
            . $product_block
            . $angle_instruction
            . $seasonal_instruction
            . 'Post angle: ' . $variety . "\n\n"
            . 'Anti-hallucination rule: Do not invent features, services, capabilities, reviews, or claims the business has not stated. '
            . 'Only reference what is described above. Reply with only the post copy, nothing else.';

        $raw = $ai['instance']->generate_raw(
            $prompt,
            $ai['api_key'],
            $ai['model'],
            512
        );

        if ($raw === '') {
            return '';
        }

        return preg_replace('/[^\x00-\x7F]/', '', trim($raw));
    }

    // ------------------------------------------------------------------
    // Store a product promotion post in wp_amai_scheduled_posts
    // ------------------------------------------------------------------
    private static function storePost(
        string $channel,
        string $content,
        string $status,
        string $batch,
        string $date
    ): void {
        global $wpdb;

        $table     = $wpdb->prefix . 'amai_scheduled_posts';
        $day_index = (int) gmdate('N') - 1;
        $post_time = BestTimeLearner::getBestTime($channel, $day_index);
        $page_id   = '';

        if ($channel === 'facebook' || $channel === 'instagram') {
            $conn    = FacebookAuth::getConnection();
            $page_id = (string) ($conn['page_id'] ?? '');
        }

        $wpdb->query(
            $wpdb->prepare(
                "INSERT INTO `{$table}`
                    (tenant_id, channel, facebook_page_id, post_type, scheduled_date, scheduled_time,
                     status, post_content, generation_batch, created_at, updated_at)
                 VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, UTC_TIMESTAMP(), UTC_TIMESTAMP())",
                'default',
                $channel,
                $page_id,
                'product_promotion',
                $date,
                $post_time,
                $status,
                $content,
                $batch
            )
        );
    }

    // ------------------------------------------------------------------
    // Detect whether we are within a seasonal window
    // ------------------------------------------------------------------
    private static function detectSeason(): string
    {
        $month = (int) gmdate('n');
        $day   = (int) gmdate('j');

        foreach (self::SEASONAL_WINDOWS as $window) {
            if ($window['month'] === $month && $day >= $window['day_start'] && $day <= $window['day_end']) {
                return $window['label'];
            }
        }

        return '';
    }

    // ------------------------------------------------------------------
    // Resolve the active AI provider
    // ------------------------------------------------------------------
    private static function resolveAiProvider(): ?array
    {
        $active_modules = (array) get_option('amai_active_modules', []);

        foreach ($active_modules as $module_id) {
            if (!is_string($module_id) || !str_starts_with($module_id, 'ai-')) {
                continue;
            }

            $file = AMAI_PLUGIN_DIR . 'modules/' . $module_id . '.php';
            if (!is_file($file)) {
                continue;
            }

            require_once $file;

            $suffix   = str_replace('-', '', ucwords(substr($module_id, 3), '-'));
            $class    = 'AutoMarketerAI\\Modules\\' . ucfirst($suffix);

            if (!class_exists($class)) {
                continue;
            }

            $instance = new $class();
            $api_key  = KeyVault::decrypt((string) get_option('amai_api_key_' . $module_id, ''));

            if ($api_key === '') {
                continue;
            }

            return [
                'instance' => $instance,
                'api_key'  => $api_key,
                'model'    => $instance->get_default_model(),
            ];
        }

        return null;
    }

    // ------------------------------------------------------------------
    // Return slugs of active connected social channels
    // ------------------------------------------------------------------
    private static function getActiveConnectedChannels(): array
    {
        $active_modules = (array) get_option('amai_active_modules', []);
        $channels       = [];

        foreach (self::CHANNEL_MAP as $auth_class => $channel_slug) {
            if (!in_array($channel_slug, $active_modules, true)) {
                continue;
            }

            if (!class_exists($auth_class)) {
                continue;
            }

            try {
                $connected = false;

                if (method_exists($auth_class, 'getConnection')) {
                    $conn      = $auth_class::getConnection();
                    $connected = $conn !== null && $conn !== false && $conn !== [];
                } elseif (method_exists($auth_class, 'is_available')) {
                    $instance  = new $auth_class();
                    $connected = $instance->is_available();
                }

                if ($connected) {
                    $channels[] = $channel_slug;
                }
            } catch (\Throwable $e) {
                // Skip -- never let one bad channel abort the run
            }
        }

        return $channels;
    }

    // ------------------------------------------------------------------
    // Next Mon/Wed/Fri at 10:30am UTC
    // ------------------------------------------------------------------
    private static function nextWeekdayTimestamp(): int
    {
        $now        = time();
        $candidates = [];

        foreach (['monday', 'wednesday', 'friday'] as $label) {
            $ts = strtotime('next ' . $label . ' 10:30:00 UTC');
            if ($ts !== false && $ts > $now) {
                $candidates[] = $ts;
            }
        }

        return !empty($candidates) ? min($candidates) : $now + DAY_IN_SECONDS;
    }
}