<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\View\View;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class AyudaIaController extends Controller
{
    public function index(Request $request): View
    {
        $empresaId = (int) (tenant_empresa_id() ?? 0);
        $userId = (int) (auth_user()?->id ?? 0);
        abort_if($empresaId <= 0 || $userId <= 0, 403, 'No hay sesión activa de empresa.');

        $idleTimeoutSeconds = $this->idleTimeoutSeconds();
        $selectedClosedSessionId = max(0, (int) $request->query('chat_cerrado', 0));

        $currentSession = $this->resolveCurrentSession($empresaId, $userId);
        $chatClosed = false;

        if (is_array($currentSession)
            && (string) ($currentSession['estado'] ?? '') === 'activa'
            && $this->isChatExpired($empresaId, $userId, $idleTimeoutSeconds, $currentSession)
        ) {
            $this->closeSession((int) ($currentSession['id'] ?? 0));
            $chatClosed = true;
            $currentSession['estado'] = 'cerrada';
        }

        if (! $chatClosed && ! is_array($currentSession) && $selectedClosedSessionId <= 0) {
            $currentSession = $this->createAndSelectSession($empresaId, $userId);
        }

        $viewSession = $currentSession;
        $viewingClosedSessionId = 0;

        if ($selectedClosedSessionId > 0) {
            $selectedSession = $this->findOwnedSession($selectedClosedSessionId, $empresaId, $userId);
            if (is_array($selectedSession) && (string) ($selectedSession['estado'] ?? '') === 'cerrada') {
                $viewSession = $selectedSession;
                $viewingClosedSessionId = (int) ($selectedSession['id'] ?? 0);
                $chatClosed = true;
            }
        }

        $messages = [];
        if (is_array($viewSession)) {
            $messages = DB::table('ai_help_messages')
                ->where('session_id', (int) ($viewSession['id'] ?? 0))
                ->where('empresa_id', $empresaId)
                ->where('usuario_id', $userId)
                ->orderBy('id')
                ->limit($this->historyLimit())
                ->get(['id', 'rol', 'contenido', 'created_at'])
                ->map(static fn ($row): array => [
                    'id' => (int) ($row->id ?? 0),
                    'rol' => (string) ($row->rol ?? 'assistant'),
                    'contenido' => (string) ($row->contenido ?? ''),
                    'created_at' => (string) ($row->created_at ?? ''),
                ])
                ->all();
        }

        if (! $chatClosed && is_array($currentSession)) {
            $currentSessionId = (int) ($currentSession['id'] ?? 0);
            if ($currentSessionId > 0) {
                $this->touchSession($currentSessionId);
                $this->touchChatSession($empresaId, $userId);
            }
        }

        $closedChats = DB::table('ai_help_sessions as s')
            ->leftJoin('ai_help_messages as m', 'm.session_id', '=', 's.id')
            ->where('s.empresa_id', $empresaId)
            ->where('s.usuario_id', $userId)
            ->where('s.estado', 'cerrada')
            ->groupBy('s.id', 's.titulo', 's.closed_at')
            ->orderByRaw('COALESCE(s.closed_at, s.updated_at) DESC')
            ->limit(12)
            ->get([
                's.id',
                's.titulo',
                's.closed_at',
                DB::raw('COUNT(m.id) as mensajes'),
            ])
            ->map(static fn ($row): array => [
                'id' => (int) ($row->id ?? 0),
                'titulo' => (string) ($row->titulo ?? 'Chat cerrado'),
                'closed_at' => (string) ($row->closed_at ?? ''),
                'mensajes' => (int) ($row->mensajes ?? 0),
            ])
            ->all();

        return view('modules.soporte.ia', [
            'assistant_config' => [
                'is_ready' => true,
            ],
            'messages' => $messages,
            'closed_chats' => $closedChats,
            'chat_closed' => $chatClosed,
            'idle_timeout_seconds' => $idleTimeoutSeconds,
            'viewing_closed_session_id' => $viewingClosedSessionId,
            'current_session_id' => is_array($viewSession) ? (int) ($viewSession['id'] ?? 0) : 0,
        ]);
    }

    public function ask(Request $request): JsonResponse
    {
        $empresaId = (int) (tenant_empresa_id() ?? 0);
        $user = auth_user();
        $userId = (int) ($user?->id ?? 0);
        if ($empresaId <= 0 || $userId <= 0) {
            return response()->json([
                'ok' => false,
                'message' => 'Sesión inválida para consultar el asistente.',
            ], 401);
        }

        $validated = $request->validate([
            'pregunta' => ['required', 'string', 'max:1200'],
        ]);

        $question = trim((string) ($validated['pregunta'] ?? ''));
        if ($question === '') {
            return response()->json([
                'ok' => false,
                'message' => 'Escribe una pregunta para continuar.',
            ], 422);
        }

        $idleTimeoutSeconds = $this->idleTimeoutSeconds();
        $currentSession = $this->resolveCurrentSession($empresaId, $userId);
        if (! is_array($currentSession)) {
            $currentSession = $this->createAndSelectSession($empresaId, $userId);
        }

        $currentSessionId = (int) ($currentSession['id'] ?? 0);
        if ($currentSessionId <= 0) {
            return response()->json([
                'ok' => false,
                'message' => 'No fue posible inicializar la sesión del chat.',
            ], 500);
        }

        if ($this->isChatExpired($empresaId, $userId, $idleTimeoutSeconds, $currentSession)) {
            $this->closeSession($currentSessionId);
            return response()->json([
                'ok' => false,
                'code' => 'chat_idle_timeout',
                'message' => 'El chat se cerró por inactividad. Pulsa "Reabrir chat" para continuar.',
            ], 440);
        }

        $answer = $this->buildAssistantAnswer($question, (string) ($user?->nombre ?? 'Operador'));
        $model = 'local:veltrix-assistant-v1';
        $now = now();

        DB::transaction(function () use ($empresaId, $userId, $currentSessionId, $question, $answer, $model, $now): void {
            DB::table('ai_help_messages')->insert([
                'session_id' => $currentSessionId,
                'empresa_id' => $empresaId,
                'usuario_id' => $userId,
                'rol' => 'user',
                'contenido' => $question,
                'modelo' => null,
                'metadata_json' => null,
                'created_at' => $now,
            ]);

            DB::table('ai_help_messages')->insert([
                'session_id' => $currentSessionId,
                'empresa_id' => $empresaId,
                'usuario_id' => $userId,
                'rol' => 'assistant',
                'contenido' => $answer,
                'modelo' => $model,
                'metadata_json' => null,
                'created_at' => $now,
            ]);
        });

        $this->touchSession($currentSessionId);
        $this->touchChatSession($empresaId, $userId);
        $this->updateTitleIfGeneric($currentSessionId, $question);

        return response()->json([
            'ok' => true,
            'answer' => $answer,
            'model' => $model,
            'chat_expires_in_seconds' => $idleTimeoutSeconds,
            'chat_expires_at' => now()->addSeconds($idleTimeoutSeconds)->toIso8601String(),
        ]);
    }

    public function reopen(Request $request): JsonResponse|RedirectResponse
    {
        $empresaId = (int) (tenant_empresa_id() ?? 0);
        $userId = (int) (auth_user()?->id ?? 0);
        if ($empresaId <= 0 || $userId <= 0) {
            return response()->json([
                'ok' => false,
                'message' => 'Sesión inválida para reabrir chat.',
            ], 401);
        }

        $targetSessionId = max(0, (int) $request->input('session_id', 0));
        if ($targetSessionId <= 0) {
            $targetSessionId = $this->currentSessionId($empresaId, $userId);
        }

        $targetSession = $targetSessionId > 0
            ? $this->findOwnedSession($targetSessionId, $empresaId, $userId)
            : null;

        if (! is_array($targetSession)) {
            $targetSession = $this->createAndSelectSession($empresaId, $userId);
            $targetSessionId = (int) ($targetSession['id'] ?? 0);
        } else {
            DB::table('ai_help_sessions')
                ->where('empresa_id', $empresaId)
                ->where('usuario_id', $userId)
                ->where('estado', 'activa')
                ->where('id', '!=', $targetSessionId)
                ->update([
                    'estado' => 'cerrada',
                    'closed_at' => now(),
                    'updated_at' => now(),
                ]);

            DB::table('ai_help_sessions')
                ->where('id', $targetSessionId)
                ->where('empresa_id', $empresaId)
                ->where('usuario_id', $userId)
                ->update([
                    'estado' => 'activa',
                    'closed_at' => null,
                    'reopened_at' => now(),
                    'last_activity_at' => now(),
                    'updated_at' => now(),
                ]);

            $this->setCurrentSessionId($empresaId, $userId, $targetSessionId);
        }

        $idleTimeoutSeconds = $this->idleTimeoutSeconds();
        $this->touchChatSession($empresaId, $userId);

        if (! $this->expectsJson($request)) {
            return redirect()
                ->route('ayuda-ia.index')
                ->with('status', 'Chat reabierto correctamente.');
        }

        return response()->json([
            'ok' => true,
            'message' => 'Chat reabierto.',
            'chat_expires_in_seconds' => $idleTimeoutSeconds,
            'chat_expires_at' => now()->addSeconds($idleTimeoutSeconds)->toIso8601String(),
        ]);
    }

    private function historyLimit(): int
    {
        return 120;
    }

    private function idleTimeoutSeconds(): int
    {
        $minutes = (int) config('ai.chat.idle_timeout_minutes', 5);

        return max(60, min(3600, $minutes * 60));
    }

    private function chatLastActivityKey(int $empresaId, int $userId): string
    {
        return '_ai_chat_last_activity_'.$empresaId.'_'.$userId;
    }

    private function chatCurrentSessionKey(int $empresaId, int $userId): string
    {
        return '_ai_chat_current_session_'.$empresaId.'_'.$userId;
    }

    private function currentSessionId(int $empresaId, int $userId): int
    {
        return (int) session($this->chatCurrentSessionKey($empresaId, $userId), 0);
    }

    private function setCurrentSessionId(int $empresaId, int $userId, int $sessionId): void
    {
        session([$this->chatCurrentSessionKey($empresaId, $userId) => $sessionId]);
    }

    private function touchChatSession(int $empresaId, int $userId): void
    {
        session([$this->chatLastActivityKey($empresaId, $userId) => time()]);
    }

    /**
     * @param  array<string, mixed>  $sessionData
     */
    private function isChatExpired(int $empresaId, int $userId, int $timeoutSeconds, array $sessionData = []): bool
    {
        $lastActivity = (int) session($this->chatLastActivityKey($empresaId, $userId), 0);
        if ($lastActivity <= 0) {
            $fromDb = trim((string) ($sessionData['last_activity_at'] ?? ''));
            if ($fromDb !== '') {
                $lastActivity = strtotime($fromDb) ?: 0;
            }
        }

        if ($lastActivity <= 0) {
            return false;
        }

        return (time() - $lastActivity) >= max(60, $timeoutSeconds);
    }

    /**
     * @return array<string, mixed>|null
     */
    private function resolveCurrentSession(int $empresaId, int $userId): ?array
    {
        $currentId = $this->currentSessionId($empresaId, $userId);
        if ($currentId > 0) {
            $session = $this->findOwnedSession($currentId, $empresaId, $userId);
            if (is_array($session)) {
                return $session;
            }
        }

        $active = DB::table('ai_help_sessions')
            ->where('empresa_id', $empresaId)
            ->where('usuario_id', $userId)
            ->where('estado', 'activa')
            ->orderByDesc('id')
            ->first();

        if (! $active) {
            return null;
        }

        $this->setCurrentSessionId($empresaId, $userId, (int) $active->id);

        return (array) $active;
    }

    /**
     * @return array<string, mixed>|null
     */
    private function findOwnedSession(int $sessionId, int $empresaId, int $userId): ?array
    {
        $row = DB::table('ai_help_sessions')
            ->where('id', $sessionId)
            ->where('empresa_id', $empresaId)
            ->where('usuario_id', $userId)
            ->first();

        return $row ? (array) $row : null;
    }

    /**
     * @return array<string, mixed>|null
     */
    private function createAndSelectSession(int $empresaId, int $userId): ?array
    {
        DB::table('ai_help_sessions')
            ->where('empresa_id', $empresaId)
            ->where('usuario_id', $userId)
            ->where('estado', 'activa')
            ->update([
                'estado' => 'cerrada',
                'closed_at' => now(),
                'updated_at' => now(),
            ]);

        $now = now();
        $sessionId = DB::table('ai_help_sessions')->insertGetId([
            'empresa_id' => $empresaId,
            'usuario_id' => $userId,
            'titulo' => 'Nuevo chat '.now()->format('d/m H:i'),
            'estado' => 'activa',
            'created_at' => $now,
            'updated_at' => $now,
            'last_activity_at' => $now,
            'closed_at' => null,
            'reopened_at' => null,
        ]);

        $this->setCurrentSessionId($empresaId, $userId, (int) $sessionId);

        return $this->findOwnedSession((int) $sessionId, $empresaId, $userId);
    }

    private function closeSession(int $sessionId): void
    {
        if ($sessionId <= 0) {
            return;
        }

        DB::table('ai_help_sessions')
            ->where('id', $sessionId)
            ->update([
                'estado' => 'cerrada',
                'closed_at' => now(),
                'updated_at' => now(),
            ]);
    }

    private function touchSession(int $sessionId): void
    {
        if ($sessionId <= 0) {
            return;
        }

        DB::table('ai_help_sessions')
            ->where('id', $sessionId)
            ->update([
                'last_activity_at' => now(),
                'updated_at' => now(),
            ]);
    }

    private function updateTitleIfGeneric(int $sessionId, string $question): void
    {
        if ($sessionId <= 0) {
            return;
        }

        $currentTitle = trim((string) DB::table('ai_help_sessions')->where('id', $sessionId)->value('titulo'));
        if ($currentTitle !== '' && ! Str::startsWith(Str::lower($currentTitle), 'nuevo chat')) {
            return;
        }

        DB::table('ai_help_sessions')
            ->where('id', $sessionId)
            ->update([
                'titulo' => Str::limit(trim($question), 150, '...'),
                'updated_at' => now(),
            ]);
    }

    private function expectsJson(Request $request): bool
    {
        $accept = strtolower((string) $request->header('Accept', ''));
        $requestedWith = strtolower((string) $request->header('X-Requested-With', ''));

        return str_contains($accept, 'application/json') || $requestedWith === 'xmlhttprequest' || $request->expectsJson();
    }

    private function buildAssistantAnswer(string $question, string $userName): string
    {
        $value = Str::lower(trim($question));

        if (str_contains($value, 'venta') || str_contains($value, 'pos')) {
            return "Para venta rápida en POS:\n1. Entra a POS.\n2. Selecciona cliente y productos.\n3. Define método de pago.\n4. Confirma en \"Registrar venta\".\n\nSi quieres, te guío paso a paso con tu caso.";
        }

        if (str_contains($value, 'caja') || str_contains($value, 'arqueo')) {
            return "Para caja:\n1. Abre caja al iniciar turno.\n2. Registra ingresos/egresos.\n3. Ejecuta cierre con arqueo al final.\n\nRevisa diferencias antes de confirmar cierre.";
        }

        if (str_contains($value, 'inventario') || str_contains($value, 'stock') || str_contains($value, 'kardex')) {
            return "Inventario recomendado:\n1. Usa Compras/Recepciones para entradas.\n2. Usa POS para salidas automáticas.\n3. Gestiona ajustes/traslados desde Inventario.\n4. Revisa kardex para trazabilidad.";
        }

        if (str_contains($value, 'compra') || str_contains($value, 'orden')) {
            return "Flujo de compras:\n1. Crea orden de compra.\n2. Recibe parcial o total.\n3. Registra pago de compra.\n4. Verifica que inventario se actualizó en la sucursal correcta.";
        }

        if (str_contains($value, 'reporte')) {
            return "En Reportes puedes filtrar por fechas, cajero y sucursal para ver ventas, utilidad, inventario, cartera y kardex. Usa \"Aplicar\" para refrescar todo el tablero.";
        }

        if (str_contains($value, 'usuario') || str_contains($value, 'permiso') || str_contains($value, 'rol')) {
            return "Para usuarios y permisos:\n1. Crea o edita usuario en Administración > Usuarios.\n2. Asigna rol según perfil (admin, cajero, bodega).\n3. Valida acceso ingresando con ese usuario.";
        }

        return "Hola {$userName}, te puedo ayudar con POS, caja, inventario, compras, ventas, reportes y permisos. Cuéntame exactamente qué flujo quieres resolver y te lo doy en pasos.";
    }
}
