<?php
declare(strict_types=1);
// ==================================================
// Nuclear Fancy Pants Edition™ -- NUCLEAR+++
// File: /home/ploi/automarketer-ai.com/public/wp-content/plugins/automarketer-ai/includes/class-nudge-engine.php
// Description: Profile completion nudge engine - state, rotation, email, snooze, dismiss, AI rewrite - NUCLEAR+++
// Last Edited: 2026-05-13
// ==================================================

namespace AutoMarketerAI;

defined('ABSPATH') || exit;

final class NudgeEngine
{
    // Nudge keys
    public const NUDGE_PROFILE  = 'profile';
    public const NUDGE_AI_COPY  = 'ai_copy';
    public const NUDGE_AI_IMAGE = 'ai_image';
    public const NUDGE_CHANNEL  = 'channel';
    public const NUDGE_LEGAL    = 'legal';
    public const NUDGE_COMMENTS = 'comments';

    // Nudges shown on overview/modules pages -- rotate together
    private const OVERVIEW_NUDGES = [
        self::NUDGE_PROFILE,
        self::NUDGE_AI_COPY,
        self::NUDGE_AI_IMAGE,
        self::NUDGE_CHANNEL,
        self::NUDGE_COMMENTS,
    ];

    // Nudges shown on settings page -- rotate independently
    private const SETTINGS_NUDGES = [
        self::NUDGE_LEGAL,
        self::NUDGE_COMMENTS,
    ];

    // All valid nudge keys -- used for validation
    private const ALL_NUDGES = [
        self::NUDGE_PROFILE,
        self::NUDGE_AI_COPY,
        self::NUDGE_AI_IMAGE,
        self::NUDGE_CHANNEL,
        self::NUDGE_LEGAL,
    ];

    // Email fires every 7 days while any nudge is unresolved
    private const EMAIL_INTERVAL_DAYS = 1;

    private static ?self $instance = null;

    public static function init(): self
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    private function __construct()
    {
        add_action('wp_ajax_amai_nudge_snooze',          [$this, 'handleSnooze']);
        add_action('wp_ajax_amai_nudge_dismiss',         [$this, 'handleDismiss']);
        add_action('wp_ajax_amai_nudge_profile_rewrite', [$this, 'handleProfileRewrite']);
        add_action('wp_ajax_amai_nudge_reset_setup',        [$this, 'handleResetSetup']);
        add_action('amai_nudge_email_check',             [$this, 'maybeSendEmail']);

        if (!wp_next_scheduled('amai_nudge_email_check')) {
            wp_schedule_event(time(), 'daily', 'amai_nudge_email_check');
        }
    }

    // Returns the nudge to show for a given page, rotating per page across page loads.
    // Page values: 'overview' (dashboard + modules), 'settings'
    public function getActiveNudgeForPage(string $page): ?string
    {
        $pool = match ($page) {
            'overview' => self::OVERVIEW_NUDGES,
            'settings' => self::SETTINGS_NUDGES,
            default    => [],
        };

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

        // Setup nudges must be shown in strict sequential order --
        // do not advance to the next step until the current one is resolved.
        $setup_sequence = [self::NUDGE_PROFILE, self::NUDGE_AI_COPY, self::NUDGE_AI_IMAGE, self::NUDGE_CHANNEL];
        $is_setup_pool  = ($pool === self::OVERVIEW_NUDGES || array_values($pool) === array_values($setup_sequence));

        if ($is_setup_pool) {
            foreach ($setup_sequence as $key) {
                if (!in_array($key, $pool, true)) {
                    continue;
                }
                if ($this->isResolved($key)) {
                    continue;
                }
                if ($this->isDismissed($key)) {
                    continue;
                }
                $this->maybeRecordFirstSeen($key);
                return $key;
            }
            // All setup nudges resolved or dismissed -- check non-setup nudges in pool
            $non_setup = array_diff($pool, $setup_sequence);
            if (empty($non_setup)) {
                return null;
            }
            $candidates = [];
            foreach ($non_setup as $key) {
                if (!$this->isResolved($key) && !$this->isDismissed($key)) {
                    $candidates[] = $key;
                }
            }
            if (empty($candidates)) {
                return null;
            }
            $key = $candidates[0];
            $this->maybeRecordFirstSeen($key);
            return $key;
        }

        // Non-setup pools: rotate through candidates
        $candidates = [];
        foreach ($pool as $key) {
            if (!$this->isResolved($key) && !$this->isDismissed($key)) {
                $candidates[] = $key;
            }
        }

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

        $option     = 'amai_nudge_rotation_' . $page;
        $last_index = (int) get_option($option, -1);
        $count      = count($candidates);
        $next_index = ($last_index + 1) % $count;
        $key        = $candidates[$next_index];

        update_option($option, $next_index, false);
        $this->maybeRecordFirstSeen($key);

        return $key;
    }

    // Backwards-compatible shim for existing callers in dashboard.php and modules.php
    public function getActiveNudge(): ?string
    {
        return $this->getActiveNudgeForPage('overview');
    }

    // True when a nudge condition is fully satisfied (independent of dismissed state)
    public function isResolved(string $key): bool
    {
        return match ($key) {
            self::NUDGE_PROFILE  => $this->isProfileComplete(),
            self::NUDGE_AI_COPY  => $this->hasAiCopyProvider(),
            self::NUDGE_AI_IMAGE => $this->hasAiImageProvider(),
            self::NUDGE_CHANNEL  => $this->hasChannel(),
            self::NUDGE_LEGAL    => $this->hasLegalPages(),
            self::NUDGE_COMMENTS => $this->hasNoUnreadComments(),
            default              => true,
        };
    }

    // Returns all unresolved, non-dismissed nudge keys -- used for the weekly email
    public function getUnresolvedNudges(): array
    {
        $unresolved = [];
        foreach (self::ALL_NUDGES as $key) {
            if (!$this->isResolved($key) && !$this->isDismissed($key)) {
                $unresolved[] = $key;
            }
        }
        return $unresolved;
    }

    // Send the weekly consolidated nudge email if due
    public function maybeSendEmail(): void
    {
        $unresolved = $this->getUnresolvedNudges();
        if (empty($unresolved)) {
            return;
        }

        $last_sent = (string) get_option('amai_nudge_last_email_sent', '');
        if ($last_sent !== '') {
            $days_since = (time() - (int) strtotime($last_sent)) / 86400;
            if ($days_since < self::EMAIL_INTERVAL_DAYS) {
                return;
            }
        }

        $this->sendConsolidatedEmail($unresolved);
        update_option('amai_nudge_last_email_sent', gmdate('Y-m-d H:i:s'));
    }

    // AJAX: snooze any snoozeable nudge for 7 days
    public function handleSnooze(): void
    {
        check_ajax_referer('amai_nudge_actions', '_ajax_nonce');

        if (!current_user_can('manage_automarketer_ai')) {
            wp_send_json_error(['message' => 'Unauthorized']);
            return;
        }

        $key = sanitize_key((string) ($_POST['nudge_key'] ?? ''));

        if (!in_array($key, self::ALL_NUDGES, true)) {
            wp_send_json_error(['message' => 'Invalid nudge key']);
            return;
        }

        $until = gmdate('Y-m-d H:i:s', strtotime('+7 days'));
        $this->upsertLog($key, ['snoozed_until' => $until]);

        wp_send_json_success(['snoozed_until' => $until]);
    }

    // AJAX: permanently dismiss a nudge
    public function handleDismiss(): void
    {
        check_ajax_referer('amai_nudge_actions', '_ajax_nonce');

        if (!current_user_can('manage_automarketer_ai')) {
            wp_send_json_error(['message' => 'Unauthorized']);
            return;
        }

        $key = sanitize_key((string) ($_POST['nudge_key'] ?? ''));

        if (!in_array($key, self::ALL_NUDGES, true)) {
            wp_send_json_error(['message' => 'Invalid nudge key']);
            return;
        }

        $this->upsertLog($key, ['dismissed_at' => gmdate('Y-m-d H:i:s')]);

        wp_send_json_success(['dismissed' => true]);
    }

    // AJAX: reset dismissed state for the 4 setup nudges so the checklist reappears
    public function handleResetSetup(): void
    {
        check_ajax_referer('amai_nudge_actions', '_ajax_nonce');
        if (!current_user_can('manage_automarketer_ai')) {
            wp_send_json_error(['message' => 'Unauthorized']);
            return;
        }
        global $wpdb;
        $table = $wpdb->prefix . 'amai_nudge_log';
        $keys  = [self::NUDGE_PROFILE, self::NUDGE_AI_COPY, self::NUDGE_AI_IMAGE, self::NUDGE_CHANNEL];
        foreach ($keys as $key) {
            $wpdb->update($table, ['dismissed_at' => null, 'snoozed_until' => null], ['nudge_key' => $key]);
        }
        wp_send_json_success(['reset' => true]);
    }
    // AJAX: rewrite the business profile differentiator using the active AI provider
    public function handleProfileRewrite(): void
    {
        check_ajax_referer('amai_nudge_actions', '_ajax_nonce');

        if (!current_user_can('manage_automarketer_ai')) {
            wp_send_json_error(['message' => 'Unauthorized']);
            return;
        }

        $active_modules = (array) get_option('amai_active_modules', []);
        $provider_id    = '';
        foreach ($active_modules as $mod) {
            if (is_string($mod) && str_starts_with($mod, 'ai-')) {
                $provider_id = $mod;
                break;
            }
        }

        if ($provider_id === '') {
            wp_send_json_error(['message' => 'No AI provider active. Activate one on the Modules page first.']);
            return;
        }

        $api_key = KeyVault::decrypt((string) get_option('amai_api_key_' . $provider_id, ''));
        $model   = (string) get_option('amai_model_' . $provider_id, '');

        if ($api_key === '' || $model === '') {
            wp_send_json_error(['message' => 'AI provider not fully configured.']);
            return;
        }

        $bp      = new BusinessProfile();
        $profile = $bp->get();

        if (!is_array($profile)) {
            wp_send_json_error(['message' => 'No business profile found.']);
            return;
        }

        $category       = BusinessProfile::BUSINESS_CATEGORIES[(string) ($profile['business_category'] ?? '')] ?? (string) ($profile['business_category'] ?? '');
        $differentiator = trim((string) ($profile['differentiator'] ?? ''));
        $website        = trim((string) ($profile['website_url'] ?? ''));

        $context = $differentiator !== ''
            ? "Here is what they wrote about what makes their business different: \"{$differentiator}\""
            : 'They have not yet described what makes their business different.';

        $website_context = $website !== ''
            ? "Their website is: {$website} - use this to inform your understanding of their business."
            : '';

        $prompt = "You are helping a small business owner describe what makes their business stand out. "
            . "Write 2-3 warm, plain-English sentences that capture what makes this business special and why customers choose them. "
            . "Do not use buzzwords, jargon, or generic marketing speak. Sound like a real person talking. "
            . "Business category: {$category}. "
            . "{$context} "
            . "{$website_context} "
            . "Return only the 2-3 sentences. No intro, no label, no explanation.";

        $module_dir = AMAI_PLUGIN_DIR . '/modules';
        $module     = null;

        if (is_dir($module_dir)) {
            $iterator = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($module_dir)
            );
            foreach ($iterator as $file) {
                if ($file->isDir() || $file->getExtension() !== 'php') {
                    continue;
                }
                $basename = $file->getBasename('.php');
                if ($basename !== $provider_id) {
                    continue;
                }
                require_once $file->getPathname();
                $clean = str_replace(['ai-', '-'], ['', ''], $basename);
                $class = '\\AutoMarketerAI\\Modules\\' . ucfirst($clean);
                if (class_exists($class)) {
                    $module = new $class();
                }
                break;
            }
        }

        if ($module === null || !method_exists($module, 'generate_raw')) {
            wp_send_json_error(['message' => 'Could not load AI provider module.']);
            return;
        }

        try {
            $result = $module->generate_raw($prompt, $api_key, $model);
            $result = trim(preg_replace('/[^\x00-\x7F]/', '', $result));

            if ($result === '') {
                wp_send_json_error(['message' => 'AI returned an empty response. Try again.']);
                return;
            }

            $bp->update(['differentiator' => $result]);

            wp_send_json_success(['differentiator' => $result]);
        } catch (\Throwable $e) {
            wp_send_json_error(['message' => 'AI rewrite failed. Please try again.']);
        }
    }

    // -- Private helpers -------------------------------------------------------

    private function isProfileComplete(): bool
    {
        $bp      = new BusinessProfile();
        $profile = $bp->get();

        if (!is_array($profile)) {
            return false;
        }

        $category       = trim((string) ($profile['business_category'] ?? ''));
        $differentiator = trim((string) ($profile['differentiator'] ?? ''));

        return $category !== '' && $differentiator !== '';
    }

    private function hasAiCopyProvider(): bool
    {
        $active = (array) get_option('amai_active_modules', []);
        foreach ($active as $mod) {
            if (is_string($mod) && str_starts_with($mod, 'ai-')) {
                return true;
            }
        }
        return false;
    }

    private function hasAiImageProvider(): bool
    {
        $active = (array) get_option('amai_active_modules', []);
        foreach ($active as $mod) {
            if (is_string($mod) && str_starts_with($mod, 'img-')) {
                return true;
            }
        }
        return false;
    }

    private function hasChannel(): bool
    {
        return FacebookAuth::getConnection() !== null
            || FacebookAuth::getInstagramAccountId() !== null;
    }

    private function hasLegalPages(): bool
    {
        // Resolved if either URL field is set, or both built-in content options are non-empty
        $privacy_url  = trim((string) get_option('amai_legal_privacy_url', ''));
        $terms_url    = trim((string) get_option('amai_legal_terms_url', ''));
        if ($privacy_url !== '' || $terms_url !== '') {
            return true;
        }
        $privacy_content = trim((string) get_option('amai_legal_privacy', ''));
        $terms_content   = trim((string) get_option('amai_legal_terms', ''));
        return $privacy_content !== '' && $terms_content !== '';
    }

    private function hasNoUnreadComments(): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_social_comments';
        $count = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM `{$table}` WHERE status IN ('new','pending_review')"
        );
        return $count === 0;
    }
    private function isSnoozed(string $key): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_nudge_log';
        $row   = $wpdb->get_row(
            $wpdb->prepare("SELECT snoozed_until FROM `{$table}` WHERE nudge_key = %s LIMIT 1", $key),
            ARRAY_A
        );

        if (!is_array($row) || empty($row['snoozed_until'])) {
            return false;
        }

        return strtotime((string) $row['snoozed_until']) > time();
    }

    private function isDismissed(string $key): bool
    {
        global $wpdb;
        $table = $wpdb->prefix . 'amai_nudge_log';
        $row   = $wpdb->get_row(
            $wpdb->prepare("SELECT dismissed_at FROM `{$table}` WHERE nudge_key = %s LIMIT 1", $key),
            ARRAY_A
        );

        if (!is_array($row) || empty($row['dismissed_at'])) {
            return false;
        }

        return true;
    }

    private function maybeRecordFirstSeen(string $key): void
    {
        global $wpdb;
        $table  = $wpdb->prefix . 'amai_nudge_log';
        $exists = $wpdb->get_var(
            $wpdb->prepare("SELECT id FROM `{$table}` WHERE nudge_key = %s LIMIT 1", $key)
        );

        if ($exists !== null) {
            return;
        }

        $wpdb->insert(
            $table,
            [
                'nudge_key'     => $key,
                'first_seen_at' => gmdate('Y-m-d H:i:s'),
            ],
            ['%s', '%s']
        );
    }

    private function upsertLog(string $key, array $fields): void
    {
        global $wpdb;
        $table  = $wpdb->prefix . 'amai_nudge_log';
        $exists = $wpdb->get_var(
            $wpdb->prepare("SELECT id FROM `{$table}` WHERE nudge_key = %s LIMIT 1", $key)
        );

        if ($exists !== null) {
            $wpdb->update($table, $fields, ['nudge_key' => $key]);
        } else {
            $wpdb->insert($table, array_merge(['nudge_key' => $key, 'first_seen_at' => gmdate('Y-m-d H:i:s')], $fields));
        }
    }

    private function sendConsolidatedEmail(array $nudge_keys): void
    {
        $admin_email = (string) get_option('admin_email', '');
        if ($admin_email === '') {
            return;
        }

        $first_name = '';
        $user       = get_user_by('email', $admin_email);
        if ($user instanceof \WP_User) {
            $first_name = (string) $user->first_name;
        }

        $items = [];
        foreach ($nudge_keys as $key) {
            $items[] = match ($key) {
                self::NUDGE_PROFILE  => 'Tell us a little about your business - it only takes a minute and it is what makes your posts sound like you.',
                self::NUDGE_AI_COPY  => 'Pick an AI provider - that is the engine that writes your posts. Claude is a great starting point.',
                self::NUDGE_AI_IMAGE => 'Add an image provider - so your posts come with eye-catching visuals automatically.',
                self::NUDGE_CHANNEL  => 'Connect Facebook or Instagram - and your first batch of posts will be ready to review.',
                self::NUDGE_LEGAL    => 'Add your privacy policy and terms of service - it keeps you covered and builds trust with visitors.',
                default              => '',
            };
        }

        $items        = array_values(array_filter($items));
        $dashboard_url = admin_url('admin.php?page=automarketer-ai');
        $subject       = 'A few things left to get you fully set up';
        $html          = \AutoMarketerAI\MarketingSite::buildSetupNudgeEmailHtml($first_name, $items, $dashboard_url);
        $headers       = ['Content-Type: text/html; charset=UTF-8'];

        wp_mail($admin_email, $subject, $html, $headers);
    }

    // --------------------------------------------------
    // Public test entry point for SettingsPage.
    // Sends a sample setup nudge email to the given address.
    // --------------------------------------------------
    public static function sendTestNudgeEmail(string $to, string $firstName): void
    {
        $nudge_items = [
            '- Tell us a little about your business - it only takes a minute and it is what makes your posts sound like you.',
            '- Pick an AI provider - that is the engine that writes your posts. Claude is a great starting point.',
            '- Connect Facebook or Instagram - and your first batch of posts will be ready to review.',
        ];
        $dashboard_url = admin_url('admin.php?page=automarketer-ai');
        $html    = MarketingSite::buildSetupNudgeEmailHtml($firstName, $nudge_items, $dashboard_url);
        $subject = 'A few things left to get you fully set up';
        $headers = ['Content-Type: text/html; charset=UTF-8'];
        wp_mail($to, $subject, $html, $headers);
    }
}
