<?php

declare(strict_types=1);

namespace App\Services;

use App\Models\GlobalSetting;

class AiHelpService
{
    private const KEY_ENABLED = 'ai_enabled';
    private const KEY_PROVIDER = 'ai_provider';
    private const KEY_OPENAI_API_KEY = 'ai_openai_api_key';
    private const KEY_OPENAI_BASE_URL = 'ai_openai_base_url';
    private const KEY_MODEL = 'ai_model';
    private const KEY_TEMPERATURE = 'ai_temperature';
    private const KEY_MAX_OUTPUT_TOKENS = 'ai_max_output_tokens';
    private const KEY_SYSTEM_PROMPT = 'ai_system_prompt';

    private static ?array $settingsCache = null;

    public function configSnapshot(): array
    {
        $config = $this->runtimeConfig();
        $apiKey = trim((string) ($config['api_key'] ?? ''));
        $model = trim((string) ($config['model'] ?? ''));
        $provider = trim((string) ($config['provider'] ?? 'openai'));

        return [
            'enabled' => (bool) ($config['enabled'] ?? false),
            'provider' => $provider !== '' ? $provider : 'openai',
            'api_key_masked' => $this->maskSecret($apiKey),
            'has_api_key' => $apiKey !== '',
            'base_url' => trim((string) ($config['base_url'] ?? 'https://api.openai.com/v1')),
            'model' => $model !== '' ? $model : 'gpt-4o-mini',
            'temperature' => (float) ($config['temperature'] ?? 0.2),
            'max_output_tokens' => (int) ($config['max_output_tokens'] ?? 700),
            'system_prompt' => (string) ($config['system_prompt'] ?? ''),
            'is_ready' => (bool) ($config['enabled'] ?? false) && $provider === 'openai' && $apiKey !== '' && $model !== '',
        ];
    }

    public function ask(string $question, array $context = []): array
    {
        $question = trim($question);
        if ($question === '') {
            return [
                'ok' => false,
                'error' => 'La pregunta está vacía.',
            ];
        }

        $config = $this->runtimeConfig();
        if (!(bool) ($config['enabled'] ?? false)) {
            return [
                'ok' => false,
                'error' => 'El agente IA está desactivado.',
            ];
        }

        $provider = trim((string) ($config['provider'] ?? 'openai'));
        if ($provider !== 'openai') {
            return [
                'ok' => false,
                'error' => 'Proveedor IA no soportado: ' . ($provider !== '' ? $provider : 'desconocido') . '.',
            ];
        }

        $apiKey = trim((string) ($config['api_key'] ?? ''));
        if ($apiKey === '') {
            return [
                'ok' => false,
                'error' => 'Falta la API key del proveedor IA.',
            ];
        }

        $model = trim((string) ($config['model'] ?? 'gpt-4o-mini'));
        if ($model === '') {
            $model = 'gpt-4o-mini';
        }

        $temperature = (float) ($config['temperature'] ?? 0.2);
        if (!is_finite($temperature)) {
            $temperature = 0.2;
        }
        $temperature = max(0.0, min(1.2, $temperature));

        $maxOutputTokens = (int) ($config['max_output_tokens'] ?? 700);
        $maxOutputTokens = max(120, min(1800, $maxOutputTokens));

        $systemPrompt = trim((string) ($config['system_prompt'] ?? ''));
        if ($systemPrompt === '') {
            $systemPrompt = 'Eres asistente de soporte de Veltrix POS. Responde en español claro, sin inventar datos.';
        }

        $userPrompt = $this->buildUserPrompt($question, $context);
        $baseUrl = rtrim((string) ($config['base_url'] ?? 'https://api.openai.com/v1'), '/');
        $endpoint = $baseUrl . '/chat/completions';

        $payload = [
            'model' => $model,
            'temperature' => $temperature,
            'max_tokens' => $maxOutputTokens,
            'messages' => [
                [
                    'role' => 'system',
                    'content' => $systemPrompt,
                ],
                [
                    'role' => 'user',
                    'content' => $userPrompt,
                ],
            ],
        ];

        $response = $this->httpPostJson($endpoint, $payload, [
            'Content-Type: application/json',
            'Accept: application/json',
            'Authorization: Bearer ' . $apiKey,
            'User-Agent: VeltrixPOS/1.0',
        ], 25);

        if (trim((string) ($response['error'] ?? '')) !== '') {
            return [
                'ok' => false,
                'error' => (string) $response['error'],
            ];
        }

        $status = (int) ($response['status'] ?? 0);
        $json = is_array($response['json'] ?? null) ? $response['json'] : [];

        if ($status < 200 || $status >= 300) {
            $apiError = trim((string) ($json['error']['message'] ?? ''));
            return [
                'ok' => false,
                'error' => $apiError !== '' ? $apiError : ('El proveedor IA respondió HTTP ' . $status . '.'),
            ];
        }

        $answer = $this->extractAnswerFromChatCompletion($json);
        if ($answer === '') {
            return [
                'ok' => false,
                'error' => 'El proveedor IA no devolvió una respuesta utilizable.',
            ];
        }

        return [
            'ok' => true,
            'answer' => $answer,
            'model' => (string) ($json['model'] ?? $model),
            'usage' => is_array($json['usage'] ?? null) ? $json['usage'] : [],
        ];
    }

    public function probe(string $question = '¿Qué módulos principales tiene Veltrix POS?'): array
    {
        return $this->ask($question, ['scope' => 'superadmin_test']);
    }

    public function clearRuntimeCache(): void
    {
        self::$settingsCache = null;
    }

    private function runtimeConfig(): array
    {
        $settings = $this->runtimeSettings();
        $provider = strtolower(trim((string) ($settings[self::KEY_PROVIDER] ?? (string) config('ai.provider', 'openai'))));
        if ($provider === '') {
            $provider = 'openai';
        }

        $temperature = (float) ($settings[self::KEY_TEMPERATURE] ?? (string) config('ai.openai.temperature', 0.2));
        $maxOutputTokens = (int) ($settings[self::KEY_MAX_OUTPUT_TOKENS] ?? (string) config('ai.openai.max_output_tokens', 700));
        $enabledRaw = (string) ($settings[self::KEY_ENABLED] ?? ((bool) config('ai.enabled', false) ? '1' : '0'));

        return [
            'enabled' => $this->toBoolean($enabledRaw),
            'provider' => $provider,
            'api_key' => trim((string) ($settings[self::KEY_OPENAI_API_KEY] ?? (string) config('ai.openai.api_key', ''))),
            'base_url' => trim((string) ($settings[self::KEY_OPENAI_BASE_URL] ?? (string) config('ai.openai.base_url', 'https://api.openai.com/v1'))),
            'model' => trim((string) ($settings[self::KEY_MODEL] ?? (string) config('ai.openai.model', 'gpt-4o-mini'))),
            'temperature' => $temperature,
            'max_output_tokens' => $maxOutputTokens,
            'system_prompt' => trim((string) ($settings[self::KEY_SYSTEM_PROMPT] ?? (string) config('ai.system_prompt', ''))),
        ];
    }

    private function runtimeSettings(): array
    {
        if (self::$settingsCache !== null) {
            return self::$settingsCache;
        }

        try {
            self::$settingsCache = (new GlobalSetting())->getMany([
                self::KEY_ENABLED,
                self::KEY_PROVIDER,
                self::KEY_OPENAI_API_KEY,
                self::KEY_OPENAI_BASE_URL,
                self::KEY_MODEL,
                self::KEY_TEMPERATURE,
                self::KEY_MAX_OUTPUT_TOKENS,
                self::KEY_SYSTEM_PROMPT,
            ]);
        } catch (\Throwable) {
            self::$settingsCache = [];
        }

        return self::$settingsCache;
    }

    private function buildUserPrompt(string $question, array $context): string
    {
        $history = is_array($context['history'] ?? null) ? $context['history'] : [];

        $lines = [
            'Contexto del operador:',
            '- Usuario: ' . trim((string) ($context['user_name'] ?? 'N/D')),
            '- Rol: ' . trim((string) ($context['role_name'] ?? 'N/D')),
            '- Empresa ID: ' . trim((string) ($context['company_id'] ?? 'N/D')),
            '- Empresa: ' . trim((string) ($context['company_name'] ?? 'N/D')),
            '- Ruta actual: ' . trim((string) ($context['current_path'] ?? 'N/D')),
            '',
        ];

        if ($history !== []) {
            $lines[] = 'Historial reciente de la conversación:';
            foreach ($history as $item) {
                if (!is_array($item)) {
                    continue;
                }

                $role = strtolower(trim((string) ($item['role'] ?? '')));
                $content = trim((string) ($item['content'] ?? ''));
                if ($content === '' || !in_array($role, ['user', 'assistant'], true)) {
                    continue;
                }

                $speaker = $role === 'user' ? 'Usuario' : 'Asistente';
                $lines[] = '- ' . $speaker . ': ' . $this->truncate($content, 1000);
            }

            $lines[] = '';
        }

        $lines[] = 'Pregunta actual del operador:';
        $lines[] = $question;

        return implode("\n", $lines);
    }

    private function extractAnswerFromChatCompletion(array $json): string
    {
        $choices = is_array($json['choices'] ?? null) ? $json['choices'] : [];
        if ($choices === []) {
            return '';
        }

        $message = is_array($choices[0]['message'] ?? null) ? $choices[0]['message'] : [];
        $content = $message['content'] ?? '';

        if (is_string($content)) {
            return trim($content);
        }

        if (is_array($content)) {
            $parts = [];
            foreach ($content as $item) {
                if (!is_array($item)) {
                    continue;
                }
                $text = trim((string) ($item['text'] ?? ''));
                if ($text !== '') {
                    $parts[] = $text;
                }
            }
            return trim(implode("\n", $parts));
        }

        return '';
    }

    private function truncate(string $value, int $length): string
    {
        if ($length <= 0) {
            return '';
        }

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

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

    private function httpPostJson(string $url, array $payload, array $headers, int $timeoutSeconds): array
    {
        if (!function_exists('curl_init')) {
            return [
                'status' => 0,
                'error' => 'cURL no está disponible en PHP.',
                'body' => null,
                'json' => null,
            ];
        }

        $ch = curl_init($url);
        if ($ch === false) {
            return [
                'status' => 0,
                'error' => 'No se pudo inicializar cURL.',
                'body' => null,
                'json' => null,
            ];
        }

        $encodedPayload = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        if (!is_string($encodedPayload) || $encodedPayload === '') {
            curl_close($ch);
            return [
                'status' => 0,
                'error' => 'No se pudo serializar el payload JSON.',
                'body' => null,
                'json' => null,
            ];
        }

        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => false,
            CURLOPT_CONNECTTIMEOUT => max(1, $timeoutSeconds),
            CURLOPT_TIMEOUT => max(1, $timeoutSeconds),
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => $encodedPayload,
            CURLOPT_HTTPHEADER => $headers,
        ]);

        $body = curl_exec($ch);
        $status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = trim((string) curl_error($ch));
        curl_close($ch);

        $json = null;
        if (is_string($body) && $body !== '') {
            $decoded = json_decode($body, true);
            if (is_array($decoded)) {
                $json = $decoded;
            }
        }

        return [
            'status' => $status,
            'error' => $error,
            'body' => is_string($body) ? $body : null,
            'json' => $json,
        ];
    }

    private function maskSecret(string $value): string
    {
        $value = trim($value);
        if ($value === '') {
            return 'No configurada';
        }

        $length = strlen($value);
        if ($length <= 8) {
            return str_repeat('*', $length);
        }

        return substr($value, 0, 4)
            . str_repeat('*', max(4, $length - 8))
            . substr($value, -4);
    }

    private function toBoolean(string $value): bool
    {
        $normalized = strtolower(trim($value));
        if ($normalized === '') {
            return false;
        }

        return in_array($normalized, ['1', 'true', 'yes', 'si', 'on'], true);
    }
}
