<?php

namespace GriffinForms\Includes\Ai\PromptRegistry\Handlers;

use GriffinForms\Includes\Ai\AiBroker;
use GriffinForms\Includes\Ai\AssistFailureFramework;
use GriffinForms\Includes\Ai\PromptRegistry\JsonExtractor;

abstract class BasePromptHandler
{
    protected AiBroker $broker;
    protected JsonExtractor $extractor;
    protected \GriffinForms\Log $log;
    protected AssistFailureFramework $failure_framework;

    public function __construct()
    {
        $this->broker = AiBroker::getInstance();
        $this->extractor = new JsonExtractor();
        $this->log = \GriffinForms\Log::getInstance();
        $this->failure_framework = new AssistFailureFramework();
    }

    abstract public function getPromptKey(): string;

    abstract public function getUnsupportedMessage(): string;

    abstract public function handle(int $form_id, string $prompt, string $provider, array $config): array;

    protected function requestStrict(string $provider, string $prompt, array $context, array $config): array
    {
        return $this->broker->requestStrict($provider, $prompt, $context, $config);
    }

    protected function normalizeText(string $value, int $limit = 255): string
    {
        $value = trim(wp_strip_all_tags($value));
        if ($value === '') {
            return '';
        }

        if (function_exists('mb_substr')) {
            return mb_substr($value, 0, $limit);
        }

        return substr($value, 0, $limit);
    }

    protected function logRetryFailure(string $prompt_key, int $attempt, array $errors, string $raw_content): void
    {
        $summary = implode(' | ', array_map('sanitize_text_field', $errors));

        $this->log->add(
            'warning',
            'ai_prompt',
            0,
            (int) get_current_user_id(),
            sprintf(
                'PromptRegistry validation retry for %s on attempt %d. Errors: %s. Raw excerpt: %s',
                sanitize_text_field($prompt_key),
                absint($attempt),
                $summary,
                sanitize_text_field(function_exists('mb_substr') ? mb_substr($raw_content, 0, 300) : substr($raw_content, 0, 300))
            ),
            'ai_reflection'
        );
    }

    protected function logBranchDecision(string $prompt_key, string $branch, int $form_id, string $prompt, array $context = []): void
    {
        $context_pairs = [];
        foreach ($context as $key => $value) {
            $context_pairs[] = sanitize_key((string) $key) . '=' . sanitize_text_field((string) $value);
        }

        $this->log->add(
            'info',
            'ai_prompt',
            $form_id,
            (int) get_current_user_id(),
            sprintf(
                'PromptRegistry branch for %s => %s prompt="%s"%s',
                sanitize_text_field($prompt_key),
                sanitize_text_field($branch),
                sanitize_text_field(function_exists('mb_substr') ? mb_substr($prompt, 0, 120) : substr($prompt, 0, 120)),
                !empty($context_pairs) ? ' ' . implode(' ', $context_pairs) : ''
            ),
            'ai_branch'
        );
    }

    protected function formatFailure(string $message, string $status = 'failed', ?int $code = null, array $context = []): array
    {
        $request_context = is_array($context['request_context'] ?? null) ? (array) $context['request_context'] : [];
        $surface = (string) ($request_context['surface'] ?? ($context['surface'] ?? 'form_builder'));
        $chat_mode = (string) ($request_context['response_mode'] ?? '') === 'text_only' || !empty($context['chat_mode']);

        return $this->failure_framework->build(
            $status,
            (int) ($code ?? 500),
            [
                'surface' => $surface,
                'chat_mode' => $chat_mode,
            ],
            $message
        );
    }

    protected function extractRequestedLanguage(string $prompt): string
    {
        if (preg_match('/\b(french|francais|fran[cç]ais|fr)\b/i', $prompt)) {
            return 'fr';
        }

        if (preg_match('/\b(spanish|espanol|espa[nñ]ol|es)\b/i', $prompt)) {
            return 'es';
        }

        if (preg_match('/\b(german|deutsch|de)\b/i', $prompt)) {
            return 'de';
        }

        if (preg_match('/\b(italian|italiano|it)\b/i', $prompt)) {
            return 'it';
        }

        if (preg_match('/\b(portuguese|portugu[êe]s|pt)\b/i', $prompt)) {
            return 'pt';
        }

        if (preg_match('/\b(dutch|nederlands|nl)\b/i', $prompt)) {
            return 'nl';
        }

        if (preg_match('/\b(hindi|main hindi|hi)\b/i', $prompt)) {
            return 'hi';
        }

        if (preg_match('/\b(punjabi|panjabi|pa-in|pa_in|pa)\b/i', $prompt)) {
            return 'pa';
        }

        return '';
    }

    protected function resolveLanguageName(string $code): string
    {
        $code = strtolower(str_replace('_', '-', $code));
        
        $map = [
            'fr' => 'French',
            'fr-fr' => 'French',
            'es' => 'Spanish',
            'es-es' => 'Spanish',
            'es-mx' => 'Spanish (Mexico)',
            'de' => 'German',
            'de-de' => 'German',
            'it' => 'Italian',
            'it-it' => 'Italian',
            'pt' => 'Portuguese',
            'pt-pt' => 'Portuguese',
            'pt-br' => 'Portuguese (Brazil)',
            'nl' => 'Dutch',
            'nl-nl' => 'Dutch',
            'hi' => 'Hindi',
            'hi-in' => 'Hindi',
            'pa' => 'Punjabi',
            'pa-in' => 'Punjabi',
        ];

        if (isset($map[$code])) {
            return $map[$code];
        }

        // Handle base codes if hyphenated wasn't found (e.g., fr-CA -> French)
        $base = explode('-', $code)[0];
        return $map[$base] ?? $code;
    }
}
