<?php
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Shared AI gateway for AI Flash Tune core and addons.
 *
 * Handles provider selection, registry defaults, privacy-safe payloads,
 * usage logging, quota checks, and response normalization in one place.
 */
class AIFLT_AI_Service {

    public static function get_zywrap_proxy_endpoint(): string {
        $endpoint = defined('AIFLT_ZYWRAP_PROXY_ENDPOINT')
            ? (string) AIFLT_ZYWRAP_PROXY_ENDPOINT
            : 'https://api.zywrap.com/v1/proxy';

        /**
         * Developer-only override for private/staging Zywrap proxy endpoints.
         * The endpoint is intentionally not editable from the admin UI.
         */
        $endpoint = apply_filters('aiflt_zywrap_proxy_endpoint', $endpoint);

        return esc_url_raw($endpoint);
    }

    public static function get_ai_language_choices(): array {
        $choices = [
            'auto'  => __('Default: WordPress/Admin language', 'ai-flash-tune'),
            'en_US' => __('English', 'ai-flash-tune'),
            'ar'    => __('Arabic', 'ai-flash-tune'),
            'es_ES' => __('Spanish', 'ai-flash-tune'),
            'de_DE' => __('German', 'ai-flash-tune'),
            'el'    => __('Greek', 'ai-flash-tune'),
            'fr_FR' => __('French', 'ai-flash-tune'),
            'pt_BR' => __('Portuguese (Brazil)', 'ai-flash-tune'),
            'it_IT' => __('Italian', 'ai-flash-tune'),
            'nl_NL' => __('Dutch', 'ai-flash-tune'),
            'ru_RU' => __('Russian', 'ai-flash-tune'),
            'ja_JP' => __('Japanese', 'ai-flash-tune'),
            'ko_KR' => __('Korean', 'ai-flash-tune'),
            'tr_TR' => __('Turkish', 'ai-flash-tune'),
            'pl_PL' => __('Polish', 'ai-flash-tune'),
            'ro_RO' => __('Romanian', 'ai-flash-tune'),
            'th_TH' => __('Thai', 'ai-flash-tune'),
            'zh_CN' => __('Chinese (Simplified)', 'ai-flash-tune'),
        ];

        return apply_filters('aiflt_ai_language_choices', $choices);
    }

    public static function get_language_name_from_locale(string $locale): string {
        $locale = trim($locale);
        $map = [
            'en' => 'English', 'en_US' => 'English', 'en_GB' => 'English',
            'ar' => 'Arabic', 'ar_SA' => 'Arabic',
            'es' => 'Spanish', 'es_ES' => 'Spanish', 'es_MX' => 'Spanish',
            'de' => 'German', 'de_DE' => 'German',
            'el' => 'Greek',
            'fr' => 'French', 'fr_FR' => 'French',
            'pt' => 'Portuguese', 'pt_BR' => 'Portuguese (Brazil)', 'pt_PT' => 'Portuguese',
            'it' => 'Italian', 'it_IT' => 'Italian',
            'nl' => 'Dutch', 'nl_NL' => 'Dutch',
            'ru' => 'Russian', 'ru_RU' => 'Russian',
            'ja' => 'Japanese', 'ja_JP' => 'Japanese',
            'ko' => 'Korean', 'ko_KR' => 'Korean',
            'tr' => 'Turkish', 'tr_TR' => 'Turkish',
            'pl' => 'Polish', 'pl_PL' => 'Polish',
            'ro' => 'Romanian', 'ro_RO' => 'Romanian',
            'th' => 'Thai', 'th_TH' => 'Thai',
            'zh' => 'Chinese', 'zh_CN' => 'Chinese (Simplified)', 'zh_TW' => 'Chinese (Traditional)',
            'cs_CZ' => 'Czech', 'fa_IR' => 'Persian', 'he_IL' => 'Hebrew', 'hu_HU' => 'Hungarian',
            'id_ID' => 'Indonesian', 'ms_MY' => 'Malay', 'sv' => 'Swedish', 'sv_SE' => 'Swedish',
            'tl_PH' => 'Tagalog', 'uk' => 'Ukrainian', 'ur' => 'Urdu',
        ];

        if (isset($map[$locale])) {
            return $map[$locale];
        }
        $short = substr($locale, 0, 2);
        if (isset($map[$short])) {
            return $map[$short];
        }
        return 'English';
    }


    /**
     * Return the language code expected by Zywrap proxy.
     *
     * WordPress locales are often regional (for example ar, ar_SA, pt_BR).
     * Zywrap wrapper translations use compact language codes. Keep this filterable
     * so future Zywrap language aliases can be adjusted without editing plugin code.
     */
    public static function get_zywrap_language_code_from_locale(string $locale): string {
        $locale = trim($locale);
        if ($locale === '') {
            return 'en';
        }

        $normalized = strtolower(str_replace('-', '_', $locale));
        $map = [
            'en' => 'en', 'en_us' => 'en', 'en_gb' => 'en',
            'ar' => 'ar', 'ar_sa' => 'ar',
            'es' => 'es', 'es_es' => 'es', 'es_mx' => 'es',
            'de' => 'de', 'de_de' => 'de',
            'el' => 'el', 'el_gr' => 'el',
            'fr' => 'fr', 'fr_fr' => 'fr',
            'pt' => 'pt', 'pt_pt' => 'pt', 'pt_br' => 'pt_br',
            'it' => 'it', 'it_it' => 'it',
            'nl' => 'nl', 'nl_nl' => 'nl',
            'ru' => 'ru', 'ru_ru' => 'ru',
            'ja' => 'ja', 'ja_jp' => 'ja',
            'ko' => 'ko', 'ko_kr' => 'ko',
            'tr' => 'tr', 'tr_tr' => 'tr',
            'pl' => 'pl', 'pl_pl' => 'pl',
            'ro' => 'ro', 'ro_ro' => 'ro',
            'th' => 'th', 'th_th' => 'th',
            'zh' => 'zh', 'zh_cn' => 'zh', 'zh_tw' => 'zh',
            'hi' => 'hi', 'hi_in' => 'hi',
            'id' => 'id', 'id_id' => 'id',
            'uk' => 'uk', 'uk_ua' => 'uk',
            'ur' => 'ur', 'ur_pk' => 'ur',
        ];

        $code = $map[$normalized] ?? substr($normalized, 0, 2);
        $code = sanitize_key($code);

        /**
         * Filter the language code sent to the Zywrap proxy payload.
         *
         * @param string $code   Compact Zywrap language code.
         * @param string $locale Original WordPress/settings locale.
         */
        return apply_filters('aiflt_zywrap_language_code', $code ?: 'en', $locale);
    }

    public static function get_ai_response_language_context($explicit = ''): array {
        $explicit = is_string($explicit) ? trim($explicit) : '';
        if ($explicit !== '') {
            return [
                'locale' => sanitize_text_field($explicit),
                'name' => self::get_language_name_from_locale($explicit),
                'source' => 'payload',
            ];
        }

        $configured = sanitize_text_field((string) get_option('aiflt_ai_response_language', 'auto'));
        if ($configured === '' || $configured === 'auto') {
            $locale = is_admin() && function_exists('get_user_locale') ? get_user_locale() : (function_exists('determine_locale') ? determine_locale() : get_locale());
            return [
                'locale' => sanitize_text_field($locale),
                'name' => self::get_language_name_from_locale((string) $locale),
                'source' => 'auto',
            ];
        }

        return [
            'locale' => $configured,
            'name' => self::get_language_name_from_locale($configured),
            'source' => 'settings',
        ];
    }

    private static function apply_ai_language_to_args(array $args): array {
        $payload = isset($args['payload']) && is_array($args['payload']) ? $args['payload'] : [];
        $explicit = '';
        if (!empty($payload['response_language']) && is_string($payload['response_language'])) {
            $explicit = (string) $payload['response_language'];
        } elseif (!empty($payload['locale']) && is_string($payload['locale'])) {
            $explicit = (string) $payload['locale'];
        }

        $language = self::get_ai_response_language_context($explicit);
        $name = sanitize_text_field((string) ($language['name'] ?? 'English'));
        $locale = sanitize_text_field((string) ($language['locale'] ?? 'en_US'));

        $instruction = sprintf(
            /* translators: 1: language name, 2: locale code. */
            __('Return the final AI-generated content in %1$s (%2$s). Keep product names, brand names, URLs, code keys, metrics, and WordPress/WooCommerce admin paths unchanged when appropriate.', 'ai-flash-tune'),
            $name,
            $locale
        );

        $args['system'] = rtrim((string) ($args['system'] ?? '')) . "\n\n### AI RESPONSE LANGUAGE\n" . $instruction;
        $args['user'] = "AI Flash Tune selected response language: " . $name . " (" . $locale . "). " . $instruction . "\n\n" . ltrim((string) ($args['user'] ?? ''));

        $payload['_aiflt_response_language'] = [
            'locale' => $locale,
            'name' => $name,
            'source' => sanitize_key((string) ($language['source'] ?? 'settings')),
        ];
        $args['payload'] = $payload;

        return $args;
    }

    public static function get_settings(): array {
        return [
            'provider' => get_option('aiflt_ai_provider', 'local'),
            'openai_key' => trim((string) get_option('aiflt_ai_api_key', '')),
            'zywrap_key' => trim((string) get_option('aiflt_zywrap_api_key', '')),
            'zywrap_endpoint' => self::get_zywrap_proxy_endpoint(),
            'model' => trim((string) get_option('aiflt_ai_model', 'gpt-4o-mini')),
            'response_language' => self::get_ai_response_language_context(),
            'external_consent' => get_option('aiflt_ai_external_consent', '0') === '1',
            'aggregate_only' => get_option('aiflt_ai_aggregate_only', '1') !== '0',
            'free_monthly_limit' => max(0, absint(get_option('aiflt_free_ai_monthly_limit', 20))),
        ];
    }

    public static function is_configured(): bool {
        $settings = self::get_settings();
        if ($settings['provider'] === 'openai') {
            return !empty($settings['openai_key']) && $settings['external_consent'];
        }
        if ($settings['provider'] === 'zywrap') {
            return !empty($settings['zywrap_key']) && $settings['external_consent'];
        }
        return false;
    }

    public static function get_status_label(): string {
        $settings = self::get_settings();
        if ($settings['provider'] === 'local') {
            return __('Local insights only', 'ai-flash-tune');
        }
        if (!self::is_configured()) {
            return __('AI engine not fully configured', 'ai-flash-tune');
        }
        return $settings['provider'] === 'zywrap' ? __('Zywrap managed AI connected', 'ai-flash-tune') : __('OpenAI connected', 'ai-flash-tune');
    }

    public static function can_use_external_ai($task = 'general'): array {
        $settings = self::get_settings();
        if ($settings['provider'] === 'local') {
            return ['allowed' => false, 'reason' => __('The AI engine is set to Local insights only.', 'ai-flash-tune')];
        }
        if (!$settings['external_consent']) {
            return ['allowed' => false, 'reason' => __('External AI sharing is disabled. Enable it in AI Settings before generating AI responses.', 'ai-flash-tune')];
        }
        if ($settings['provider'] === 'openai' && empty($settings['openai_key'])) {
            return ['allowed' => false, 'reason' => __('OpenAI API key is missing.', 'ai-flash-tune')];
        }
        if ($settings['provider'] === 'zywrap' && empty($settings['zywrap_key'])) {
            return ['allowed' => false, 'reason' => __('Zywrap API key is missing.', 'ai-flash-tune')];
        }
        if (!self::has_free_quota($task)) {
            return ['allowed' => false, 'reason' => __('Monthly free AI action limit reached for this site.', 'ai-flash-tune')];
        }
        return ['allowed' => true, 'reason' => ''];
    }

    public static function get_usage_key(): string {
        return 'aiflt_ai_usage_' . gmdate('Y_m');
    }

    public static function get_usage(): array {
        $usage = get_option(self::get_usage_key(), []);
        return is_array($usage) ? $usage : [];
    }

    public static function has_free_quota($task = 'general'): bool {
        if (class_exists('AIFLT_License_Manager') && AIFLT_License_Manager::is_pro_user()) {
            return true;
        }
        $settings = self::get_settings();
        if ($settings['free_monthly_limit'] <= 0) {
            return true;
        }

        if (class_exists('AIFLT_AI_Usage_Log')) {
            return AIFLT_AI_Usage_Log::get_monthly_total() < $settings['free_monthly_limit'];
        }

        $usage = self::get_usage();
        $total = isset($usage['total']) ? absint($usage['total']) : 0;
        return $total < $settings['free_monthly_limit'];
    }

    private static function record_usage_option($task): void {
        $key = self::get_usage_key();
        $usage = self::get_usage();
        $usage['total'] = isset($usage['total']) ? absint($usage['total']) + 1 : 1;
        $usage['tasks'] = isset($usage['tasks']) && is_array($usage['tasks']) ? $usage['tasks'] : [];
        $task = sanitize_key($task ?: 'general');
        $usage['tasks'][$task] = isset($usage['tasks'][$task]) ? absint($usage['tasks'][$task]) + 1 : 1;
        $usage['updated_at'] = current_time('mysql');
        update_option($key, $usage, false);
    }

    public static function run_action(string $action_key, array $payload = [], array $args = []): array {
        $action_key = sanitize_key($action_key);

        if (!class_exists('AIFLT_AI_Action_Registry')) {
            return [
                'status' => 'error',
                'provider' => 'local',
                'content' => $args['local_fallback'] ?? '',
                'message' => __('AI action registry is not loaded.', 'ai-flash-tune'),
            ];
        }

        if (!AIFLT_AI_Action_Registry::exists($action_key)) {
            return [
                'status' => 'error',
                'provider' => 'local',
                'content' => $args['local_fallback'] ?? '',
                'message' => sprintf(
                    /* translators: %s: AI action key. */
                    __('Unknown AI action: %s', 'ai-flash-tune'),
                    $action_key
                ),
            ];
        }

        $action = AIFLT_AI_Action_Registry::get($action_key);
        $privacy = isset($action['privacy']) ? sanitize_key((string) $action['privacy']) : 'aggregate_only';
        $safe_payload = class_exists('AIFLT_AI_Payload_Sanitizer')
            ? AIFLT_AI_Payload_Sanitizer::sanitize($payload, $privacy)
            : AIFLT_AI_Action_Registry::sanitize_payload($payload);

        if (class_exists('AIFLT_AI_Action_Registry')) {
            $readiness = AIFLT_AI_Action_Registry::validate_min_data($action_key, $safe_payload);
            $safe_payload['_data_readiness'] = $readiness;
        }

        if (empty($args['user'])) {
            $instructions = isset($args['instructions']) ? (string) $args['instructions'] : '';
            if (!empty($safe_payload['_data_readiness']) && empty($safe_payload['_data_readiness']['met'])) {
                $instructions .= "\n" . __('Data may be limited. Mention data confidence and avoid strong claims when signals are below recommended thresholds.', 'ai-flash-tune');
            }
            $args['user'] = AIFLT_AI_Action_Registry::build_user_prompt($action_key, $safe_payload, $instructions);
        }

        $args['payload'] = $safe_payload;
        $args = AIFLT_AI_Action_Registry::prepare_args($action_key, $args);

        return self::generate($args);
    }

    public static function generate(array $args): array {
        $started = microtime(true);
        $defaults = [
            'task' => 'general',
            'system' => __('You are a concise WooCommerce conversion analyst. Give specific, practical advice. Avoid hype.', 'ai-flash-tune'),
            'user' => '',
            'max_tokens' => 600,
            'temperature' => 0.4,
            'local_fallback' => '',
            'payload' => [],
        ];
        $args = wp_parse_args($args, $defaults);
        $args['task'] = sanitize_key((string) $args['task']);

        if (class_exists('AIFLT_AI_Action_Registry') && AIFLT_AI_Action_Registry::exists($args['task'])) {
            $args = AIFLT_AI_Action_Registry::prepare_args($args['task'], $args);
        }

        $args = self::apply_ai_language_to_args($args);

        $settings = self::get_settings();
        $provider = sanitize_key((string) $settings['provider']);

        if ($provider === 'local') {
            $result = [
                'status' => 'local',
                'provider' => 'local',
                'content' => $args['local_fallback'] ?: __('AI engine is not connected yet. Local free insights are available on the dashboard, and external AI can be enabled in Settings.', 'ai-flash-tune'),
                'message' => '',
            ];
            self::log_result($args, $settings, $result, $started);
            return $result;
        }

        $permission = self::can_use_external_ai($args['task']);
        if (!$permission['allowed']) {
            $fallback = isset($args['local_fallback']) ? trim((string) $args['local_fallback']) : '';
            $result = [
                // When a safe local fallback exists, return it as a successful local result.
                // This keeps Product Optimizer, Cart Recovery, Segmentation, and other modules useful
                // even when consent, provider setup, quota, or API availability blocks external AI.
                'status' => $fallback !== '' ? 'local' : 'error',
                'provider' => $fallback !== '' ? 'local' : $provider,
                'content' => $fallback,
                'message' => $permission['reason'],
            ];
            self::log_result($args, $settings, $result, $started);
            return $result;
        }

        $messages = [
            ['role' => 'system', 'content' => (string) $args['system']],
            ['role' => 'user', 'content' => (string) $args['user']],
        ];

        if ($provider === 'zywrap') {
            $result = self::call_zywrap($messages, $args, $settings);
        } else {
            $result = self::call_openai($messages, $args, $settings);
        }

        if ($result['status'] === 'success') {
            self::record_usage_option($args['task']);
        }
        self::log_result($args, $settings, $result, $started);

        return $result;
    }

    private static function log_result(array $args, array $settings, array $result, float $started): void {
        if (!class_exists('AIFLT_AI_Usage_Log')) {
            return;
        }
        $payload = isset($args['payload']) && is_array($args['payload']) ? $args['payload'] : [];
        $payload_hash = class_exists('AIFLT_AI_Payload_Sanitizer') ? AIFLT_AI_Payload_Sanitizer::hash_payload($payload) : hash('sha256', wp_json_encode($payload));
        $wrapper = isset($args['zywrap_wrapper_code']) ? (string) $args['zywrap_wrapper_code'] : '';
        if ($wrapper === '' && class_exists('AIFLT_AI_Action_Registry')) {
            $wrapper = AIFLT_AI_Action_Registry::get_wrapper_code((string) $args['task']);
        }

        AIFLT_AI_Usage_Log::log([
            'action_key' => $args['task'] ?? 'general',
            'provider' => $result['provider'] ?? ($settings['provider'] ?? 'local'),
            'wrapper_code' => $wrapper,
            'model' => $settings['model'] ?? '',
            'status' => $result['status'] ?? 'unknown',
            'message' => $result['message'] ?? '',
            'payload_hash' => $payload_hash,
            'duration_ms' => (int) round((microtime(true) - $started) * 1000),
            'prompt_tokens' => isset($result['usage']['prompt_tokens']) ? absint($result['usage']['prompt_tokens']) : 0,
            'completion_tokens' => isset($result['usage']['completion_tokens']) ? absint($result['usage']['completion_tokens']) : 0,
            'total_tokens' => isset($result['usage']['total_tokens']) ? absint($result['usage']['total_tokens']) : 0,
            'estimated_cost' => isset($result['usage']['estimated_cost']) ? (float) $result['usage']['estimated_cost'] : 0,
        ]);

        if (class_exists('AIFLT_AI_Report_Log')) {
            $content = isset($result['content']) ? (string) $result['content'] : '';
            $message = isset($result['message']) ? (string) $result['message'] : '';
            if (trim($content) !== '' || trim($message) !== '') {
                AIFLT_AI_Report_Log::save([
                    'action_key' => $args['task'] ?? 'general',
                    'provider' => $result['provider'] ?? ($settings['provider'] ?? 'local'),
                    'status' => $result['status'] ?? 'unknown',
                    'title' => class_exists('AIFLT_AI_Action_Registry') ? AIFLT_AI_Action_Registry::get_label((string) ($args['task'] ?? 'general')) : (string) ($args['task'] ?? 'general'),
                    'context_key' => self::derive_report_context_key($args),
                    'content' => $content,
                    'message' => $message,
                    'payload_hash' => $payload_hash,
                ]);
            }
        }
    }

    private static function derive_report_context_key(array $args): string {
        $payload = isset($args['payload']) && is_array($args['payload']) ? $args['payload'] : [];
        if (isset($payload['product_context']['id'])) {
            return 'product:' . absint($payload['product_context']['id']);
        }
        if (isset($payload['email_step'])) {
            return 'email_step:' . sanitize_key((string) $payload['email_step']);
        }
        if (isset($payload['preset'])) {
            return 'preset:' . sanitize_key((string) $payload['preset']);
        }
        if (isset($payload['segment_a']['label']) || isset($payload['segment_b']['label'])) {
            return 'segments:' . md5(wp_json_encode([$payload['segment_a'] ?? [], $payload['segment_b'] ?? []]));
        }
        return '';
    }

    private static function call_openai(array $messages, array $args, array $settings): array {
        $response = wp_remote_post('https://api.openai.com/v1/chat/completions', [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . sanitize_text_field($settings['openai_key']),
            ],
            'body' => wp_json_encode([
                'model' => sanitize_text_field($settings['model']),
                'messages' => $messages,
                'max_tokens' => absint($args['max_tokens']),
                'temperature' => (float) $args['temperature'],
            ]),
            'timeout' => 45,
        ]);

        return self::handle_chat_response($response, 'openai');
    }

    private static function call_zywrap(array $messages, array $args, array $settings): array {
        $endpoint = esc_url_raw($settings['zywrap_endpoint']);
        $wrapper_code = '';
        if (!empty($args['zywrap_wrapper_code'])) {
            $wrapper_code = sanitize_text_field((string) $args['zywrap_wrapper_code']);
        } elseif (class_exists('AIFLT_AI_Action_Registry')) {
            $wrapper_code = AIFLT_AI_Action_Registry::get_wrapper_code((string) $args['task']);
        }

        if ($wrapper_code === '') {
            return [
                'status' => 'error',
                'provider' => 'zywrap',
                'content' => '',
                'message' => __('No Zywrap wrapper code is mapped for this AI action yet.', 'ai-flash-tune'),
            ];
        }

        $is_proxy_endpoint = (strpos($endpoint, '/proxy') !== false);
        $variables = isset($args['payload']) && is_array($args['payload']) ? $args['payload'] : [];
        $language_context = isset($variables['_aiflt_response_language']) && is_array($variables['_aiflt_response_language'])
            ? $variables['_aiflt_response_language']
            : (isset($settings['response_language']) && is_array($settings['response_language']) ? $settings['response_language'] : self::get_ai_response_language_context());
        $zywrap_language = self::get_zywrap_language_code_from_locale((string) ($language_context['locale'] ?? 'en_US'));

        if ($is_proxy_endpoint) {
            $payload = [
                'model' => self::map_zywrap_model((string) $settings['model']),
                'wrapperCodes' => [$wrapper_code],
                'prompt' => self::messages_to_prompt($messages),
                'variables' => $variables,
                'source' => 'ai_flash_tune_wordpress',
            ];

            if ($zywrap_language !== '') {
                $payload['language'] = $zywrap_language;
            }
        } else {
            $payload = [
                'model' => sanitize_text_field($settings['model']),
                'messages' => $messages,
                'max_tokens' => absint($args['max_tokens']),
                'temperature' => (float) $args['temperature'],
                'wrapperCodes' => [$wrapper_code],
                'metadata' => [
                    'source' => 'ai-flash-tune',
                    'task' => sanitize_key($args['task']),
                    'action_label' => class_exists('AIFLT_AI_Action_Registry') ? AIFLT_AI_Action_Registry::get_label((string) $args['task']) : sanitize_key($args['task']),
                ],
            ];
        }

        $response = wp_remote_post($endpoint, [
            'headers' => [
                'Content-Type' => 'application/json',
                'Authorization' => 'Bearer ' . sanitize_text_field($settings['zywrap_key']),
                'X-AI-Flash-Tune' => AIFLT_VERSION,
            ],
            'body' => wp_json_encode($payload),
            'timeout' => 45,
        ]);

        return self::handle_chat_response($response, 'zywrap');
    }

    private static function map_zywrap_model(string $model): string {
        $model = trim($model);
        $map = [
            'gpt-4o-mini' => 'openai-gpt-4o-mini',
            'gpt-4o' => 'openai-gpt-4o',
            'openai/gpt-4o-mini' => 'openai-gpt-4o-mini',
            'openai/gpt-4o' => 'openai-gpt-4o',
        ];
        return isset($map[$model]) ? $map[$model] : $model;
    }

    private static function messages_to_prompt(array $messages): string {
        $parts = [];
        foreach ($messages as $message) {
            if (!is_array($message)) {
                continue;
            }
            $role = isset($message['role']) ? ucfirst(sanitize_key((string) $message['role'])) : 'Message';
            $content = isset($message['content']) ? (string) $message['content'] : '';
            if ($content !== '') {
                $parts[] = $role . ":\n" . $content;
            }
        }
        return implode("\n\n", $parts);
    }

    private static function decode_ai_response_body($raw_body) {
        $raw_body = is_string($raw_body) ? trim($raw_body) : '';
        if ($raw_body === '') {
            return '';
        }
        $body = json_decode($raw_body, true);
        if (json_last_error() === JSON_ERROR_NONE) {
            return $body;
        }
        $events = [];
        foreach (preg_split('/\r\n|\r|\n/', $raw_body) as $line) {
            $line = trim($line);
            if ($line === '' || stripos($line, 'data:') !== 0) {
                continue;
            }
            $payload = trim(substr($line, 5));
            if ($payload === '' || $payload === '[DONE]') {
                continue;
            }
            $decoded = json_decode($payload, true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $events[] = $decoded;
            }
        }
        if (!empty($events)) {
            for ($i = count($events) - 1; $i >= 0; $i--) {
                $candidate_content = self::extract_ai_content($events[$i]);
                if ($candidate_content !== '') {
                    return $events[$i];
                }
            }
            return end($events);
        }
        return $raw_body;
    }

    private static function extract_ai_content($body): string {
        if (is_string($body)) {
            $body = trim($body);
            if ($body === '') {
                return '';
            }
            if (stripos($body, 'data:') === 0 || preg_match('/^\s*data:\s*/m', $body)) {
                $decoded = self::decode_ai_response_body($body);
                if ($decoded !== $body) {
                    return self::extract_ai_content($decoded);
                }
            }
            $decoded = json_decode($body, true);
            if (json_last_error() === JSON_ERROR_NONE && $decoded !== null) {
                $content = self::extract_ai_content($decoded);
                if ($content !== '') {
                    return $content;
                }
            }
            return self::normalize_ai_text($body);
        }
        if (!is_array($body)) {
            return '';
        }
        $paths = [
            ['choices', 0, 'message', 'content'], ['choices', 0, 'text'], ['output'], ['content'], ['text'], ['response'], ['result'], ['message'],
            ['data', 'output'], ['data', 'content'], ['data', 'text'], ['data', 'response'], ['data', 'result'], ['data', 'message'],
            ['data', 'data', 'output'], ['data', 'data', 'content'], ['data', 'choices', 0, 'message', 'content'], ['data', 'choices', 0, 'text'],
        ];
        foreach ($paths as $path) {
            $value = $body;
            foreach ($path as $key) {
                if (is_array($value) && array_key_exists($key, $value)) {
                    $value = $value[$key];
                } else {
                    $value = null;
                    break;
                }
            }
            $content = self::normalize_ai_content_value($value);
            if ($content !== '') {
                return $content;
            }
        }
        return self::normalize_ai_content_value($body);
    }

    private static function normalize_ai_text(string $text): string {
        $text = trim($text);
        if ($text === '') {
            return '';
        }
        $text = str_replace(["\\r\\n", "\\n", "\\t"], ["\n", "\n", "\t"], $text);
        $text = preg_replace('/^data:\s*/i', '', $text);
        return trim((string) $text);
    }

    private static function normalize_ai_content_value($value): string {
        if (is_string($value)) {
            return self::normalize_ai_text($value);
        }
        if (is_numeric($value)) {
            return trim((string) $value);
        }
        if (is_array($value)) {
            foreach (['output', 'content', 'text', 'response', 'result'] as $key) {
                if (isset($value[$key])) {
                    $content = self::normalize_ai_content_value($value[$key]);
                    if ($content !== '') {
                        return $content;
                    }
                }
            }
            if (isset($value['message']) && is_array($value['message']) && isset($value['message']['content'])) {
                return self::normalize_ai_content_value($value['message']['content']);
            }
            if (isset($value['message']) && is_string($value['message'])) {
                return self::normalize_ai_content_value($value['message']);
            }
            // Preserve strict JSON objects returned by Zywrap/OpenAI so addon renderers
            // can display them as structured reports instead of flattened raw text.
            if ($value !== [] && array_keys($value) !== range(0, count($value) - 1)) {
                return wp_json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
            }
            $parts = [];
            foreach ($value as $item) {
                $content = self::normalize_ai_content_value($item);
                if ($content !== '') {
                    $parts[] = $content;
                }
            }
            return trim(implode("\n", array_filter($parts)));
        }
        return '';
    }

    private static function handle_chat_response($response, $provider): array {
        if (is_wp_error($response)) {
            return [
                'status' => 'error',
                'provider' => $provider,
                'content' => '',
                'message' => $response->get_error_message(),
            ];
        }

        $code = (int) wp_remote_retrieve_response_code($response);
        $raw_body = wp_remote_retrieve_body($response);
        $body = self::decode_ai_response_body($raw_body);

        if ($code < 200 || $code >= 300) {
            $message = __('External AI service returned an error.', 'ai-flash-tune');
            if (is_array($body)) {
                $message = $body['error']['message'] ?? $body['message'] ?? $message;
            } elseif (is_string($body) && $body !== '') {
                $message = $body;
            }
            return [
                'status' => 'error',
                'provider' => $provider,
                'content' => '',
                'message' => sprintf(
                    /* translators: 1: HTTP response code, 2: external AI service error message. */
                    __('AI request failed (%1$s): %2$s', 'ai-flash-tune'),
                    $code,
                    wp_strip_all_tags((string) $message)
                ),
            ];
        }

        $content = self::extract_ai_content($body);
        if ($content === '') {
            return [
                'status' => 'error',
                'provider' => $provider,
                'content' => '',
                'message' => __('AI response was empty or in an unsupported format.', 'ai-flash-tune'),
            ];
        }

        $usage = [];
        if (is_array($body) && isset($body['usage']) && is_array($body['usage'])) {
            $usage = [
                'prompt_tokens' => absint($body['usage']['prompt_tokens'] ?? 0),
                'completion_tokens' => absint($body['usage']['completion_tokens'] ?? 0),
                'total_tokens' => absint($body['usage']['total_tokens'] ?? 0),
                'estimated_cost' => 0,
            ];
        }

        return [
            'status' => 'success',
            'provider' => $provider,
            'content' => wp_kses_post((string) $content),
            'message' => '',
            'usage' => $usage,
        ];
    }

    public static function compact_store_context(): array {
        $context = [];
        if (class_exists('AIFLT_Funnel_Analyzer_Logic')) {
            $context['dashboard_metrics'] = AIFLT_Funnel_Analyzer_Logic::get_dashboard_metrics();
            $context['funnel'] = AIFLT_Funnel_Analyzer_Logic::get_funnel_data('all');
            $context['top_drop_off'] = AIFLT_Funnel_Analyzer_Logic::get_top_drop_off_metrics();
            $context['checkout_fields'] = AIFLT_Funnel_Analyzer_Logic::get_checkout_field_data();
            $context['page_speed'] = AIFLT_Funnel_Analyzer_Logic::get_page_speed_alerts();
        }
        if (class_exists('AIFLT_Products_Logic')) {
            $context['low_performing_products'] = AIFLT_Products_Logic::get_low_performing_products_for_dashboard(5);
        }
        if (class_exists('AIFLT_Free_Insights_Logic')) {
            $context['top_abandoned_products'] = AIFLT_Free_Insights_Logic::get_top_abandoned_products(5, 30);
        }
        return class_exists('AIFLT_AI_Payload_Sanitizer') ? AIFLT_AI_Payload_Sanitizer::sanitize($context, 'aggregate_only') : $context;
    }

    public static function test_provider(string $action_key = 'free_weekly_ai_report'): array {
        return self::run_action($action_key, [
            'test_mode' => true,
            'store_context' => [
                'platform' => 'WooCommerce',
                'sessions' => 3,
                'conversion_rate' => 0,
                'note' => 'Connectivity test from AI Flash Tune settings.'
            ],
        ], [
            'instructions' => __('Return one short sentence confirming the AI engine is reachable. Do not analyze the store.', 'ai-flash-tune'),
            'local_fallback' => __('Local mode is active. No external AI request was made.', 'ai-flash-tune'),
            'max_tokens' => 80,
        ]);
    }
}
