import React, { useState, useEffect, useRef, useCallback } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
    Loader2,
    Cable,
    CheckCircle2,
    XCircle,
    Clock,
    AlertCircle,
    Usb,
    RefreshCw,
    WifiOff,
} from "lucide-react";
import { transbankPOSIntegradoService } from "@/services/TransbankPOSIntegradoService";

const STATUS_LABELS = {
    initializing: "Inicializando...",
    checking_agent: "Verificando Agente Desktop...",
    agent_offline: "Agente Desktop no detectado",
    connecting_agent: "Conectando con el Agente POS...",
    opening_port: "Abriendo puerto serial...",
    polling: "Verificando terminal POS...",
    pending: "Esperando pago en el terminal...",
    approved: "Pago aprobado",
    rejected: "Pago rechazado",
    timeout: "Tiempo de espera agotado",
    error: "Error de conexión",
};

const CARD_TYPES = { DB: "Débito", CR: "Crédito", NB: "No Bancario" };
const CARD_BRANDS = { VI: "Visa", MC: "Mastercard", AX: "American Express", MG: "Magna", RD: "Redcompra" };

const AGENT_CHECK_TIMEOUT_MS = 3000;

/**
 * Intenta conectar al Agente Desktop via WebSocket con un timeout estricto.
 * Retorna true si el agente responde, false si no.
 */
function checkAgentAvailable(agentUrl) {
    return new Promise((resolve) => {
        let settled = false;
        const settle = (result) => {
            if (settled) return;
            settled = true;
            clearTimeout(timer);
            try { ws.close(); } catch { /* ignore */ }
            resolve(result);
        };

        let ws;
        try {
            ws = new WebSocket(agentUrl);
        } catch {
            resolve(false);
            return;
        }

        const timer = setTimeout(() => settle(false), AGENT_CHECK_TIMEOUT_MS);
        ws.onopen = () => settle(true);
        ws.onerror = () => settle(false);
        ws.onclose = () => settle(false);
    });
}

export default function TransbankPOSPaymentModal({
    amount,
    portName,
    baudRate = 115200,
    agentWsUrl = "ws://localhost:8090",
    onSuccess,
    onCancel,
}) {
    const [status, setStatus] = useState("initializing");
    const [message, setMessage] = useState("Iniciando conexión con el terminal POS...");
    const [intermediateMessages, setIntermediateMessages] = useState([]);
    const [transactionDetails, setTransactionDetails] = useState(null);
    const [ticketId] = useState(() => `TKT-${Date.now()}`);
    const [secondsElapsed, setSecondsElapsed] = useState(0);
    const cancelledRef = useRef(false);
    const timerRef = useRef(null);

    const addIntermediateMessage = (msg) => {
        setIntermediateMessages((prev) => [...prev.slice(-3), msg]);
    };

    const initializePayment = useCallback(async () => {
        if (cancelledRef.current) return;

        setIntermediateMessages([]);
        setTransactionDetails(null);

        try {
            if (!portName) {
                setStatus("error");
                setMessage("No se ha configurado el puerto del terminal POS. Configure el POS en Ajustes → Transbank → POS Integrado.");
                return;
            }

            // Paso 1: verificar que el Agente Desktop está corriendo
            setStatus("checking_agent");
            setMessage(STATUS_LABELS.checking_agent);

            const agentAvailable = await checkAgentAvailable(agentWsUrl);

            if (cancelledRef.current) return;

            if (!agentAvailable) {
                setStatus("agent_offline");
                setMessage(STATUS_LABELS.agent_offline);
                return;
            }

            // Paso 2: abrir puerto serial
            setStatus("opening_port");
            setMessage(`Abriendo ${portName} a ${baudRate} bps...`);
            const opened = await transbankPOSIntegradoService.openPort(portName, baudRate);

            if (cancelledRef.current) return;

            if (!opened) {
                setStatus("error");
                setMessage(`No se pudo abrir el puerto ${portName}. Verifique que el terminal está conectado y el driver instalado.`);
                return;
            }

            // Paso 3: poll para verificar que el POS responde
            setStatus("polling");
            setMessage(STATUS_LABELS.polling);
            const connected = await transbankPOSIntegradoService.poll();

            if (cancelledRef.current) return;

            if (!connected) {
                setStatus("error");
                setMessage("El terminal POS no responde. Verifique que esté encendido y en modo POS Integrado.");
                await transbankPOSIntegradoService.closePort();
                return;
            }

            // Paso 4: ejecutar venta
            setStatus("pending");
            setMessage(STATUS_LABELS.pending);

            const response = await transbankPOSIntegradoService.doSale(
                amount,
                ticketId,
                (msg) => {
                    if (!cancelledRef.current) addIntermediateMessage(msg);
                },
            );

            if (cancelledRef.current) return;

            await transbankPOSIntegradoService.closePort();

            if (response.success) {
                setStatus("approved");
                setMessage(STATUS_LABELS.approved);
                setTransactionDetails(response);
                setTimeout(() => {
                    if (!cancelledRef.current) {
                        onSuccess({
                            authorization_code: response.authorizationCode,
                            card_last_digits: response.last4Digits,
                            card_type: response.cardType,
                            card_brand: response.cardBrand,
                            operation_number: response.operationNumber,
                            amount: response.amount,
                            ticket: response.ticket,
                            terminal_id: response.terminalId,
                        });
                    }
                }, 2000);
            } else {
                setStatus("rejected");
                setMessage(`Pago rechazado (código ${response.responseCode}). Por favor intente nuevamente.`);
                setTransactionDetails(response);
            }
        } catch (error) {
            if (!cancelledRef.current) {
                setStatus("error");
                setMessage(`Error: ${error?.message ?? "Error inesperado en el terminal POS."}`);
                transbankPOSIntegradoService.closePort().catch(() => {});
            }
        }
    }, [amount, agentWsUrl, baudRate, portName, ticketId, onSuccess]);

    useEffect(() => {
        timerRef.current = setInterval(() => {
            setSecondsElapsed((prev) => prev + 1);
        }, 1000);

        initializePayment();

        return () => {
            if (timerRef.current) clearInterval(timerRef.current);
            if (!cancelledRef.current) {
                transbankPOSIntegradoService.closePort().catch(() => {});
            }
        };
    }, []);

    const handleRetry = () => {
        setSecondsElapsed(0);
        initializePayment();
    };

    const handleCancel = () => {
        cancelledRef.current = true;
        if (timerRef.current) clearInterval(timerRef.current);
        transbankPOSIntegradoService.closePort().catch(() => {});
        onCancel();
    };

    const getStatusIcon = () => {
        switch (status) {
            case "initializing":
            case "checking_agent":
            case "connecting_agent":
            case "opening_port":
            case "polling":
                return <Loader2 className="w-16 h-16 text-blue-600 animate-spin" />;
            case "agent_offline":
                return <WifiOff className="w-16 h-16 text-amber-500" />;
            case "pending":
                return (
                    <div className="relative flex items-center justify-center">
                        <Usb className="w-16 h-16 text-blue-600" />
                        <span className="absolute -bottom-1 -right-1 flex h-5 w-5">
                            <span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-blue-400 opacity-75" />
                            <span className="relative inline-flex rounded-full h-5 w-5 bg-blue-500" />
                        </span>
                    </div>
                );
            case "approved":
                return <CheckCircle2 className="w-16 h-16 text-green-600" />;
            case "rejected":
                return <XCircle className="w-16 h-16 text-red-600" />;
            case "timeout":
                return <Clock className="w-16 h-16 text-amber-600" />;
            case "error":
                return <AlertCircle className="w-16 h-16 text-red-600" />;
            default:
                return <Cable className="w-16 h-16 text-gray-400" />;
        }
    };

    const getCardClass = () => {
        switch (status) {
            case "approved":
                return "bg-green-50 border-green-200";
            case "rejected":
            case "error":
                return "bg-red-50 border-red-200";
            case "agent_offline":
                return "bg-amber-50 border-amber-200";
            case "timeout":
                return "bg-amber-50 border-amber-200";
            default:
                return "bg-blue-50 border-blue-200";
        }
    };

    const isTerminal = ["approved", "rejected", "timeout", "error"].includes(status);
    const isAgentOffline = status === "agent_offline";
    const isPending = status === "pending";

    return (
        <div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4" style={{ zIndex: 9999 }}>
            <Card className={`max-w-md w-full border-2 ${getCardClass()}`}>
                <CardHeader>
                    <CardTitle className="flex items-center justify-between">
                        <span className="flex items-center gap-2">
                            <Cable className="w-5 h-5" />
                            Pago Transbank POS Integrado
                        </span>
                        <Badge variant={status === "approved" ? "default" : "outline"}>
                            ${Math.round(amount).toLocaleString("es-CL")}
                        </Badge>
                    </CardTitle>
                </CardHeader>

                <CardContent className="space-y-5">
                    <div className="flex justify-center py-4">
                        {getStatusIcon()}
                    </div>

                    <div className="text-center space-y-1">
                        <p className="text-lg font-semibold text-gray-900">{message}</p>
                        {isPending && (
                            <p className="text-sm text-gray-500">
                                Tiempo transcurrido: {secondsElapsed}s
                            </p>
                        )}
                    </div>

                    {isAgentOffline && (
                        <div className="bg-amber-100 border border-amber-300 rounded-lg p-4 text-sm text-amber-900 space-y-2">
                            <p className="font-semibold">El Agente Desktop de Transbank no está corriendo en este equipo.</p>
                            <ol className="list-decimal list-inside space-y-1 text-xs">
                                <li>Descarga e instala el <strong>Agente Desktop</strong> desde <a href="https://github.com/TransbankDevelopers/transbank-pos-sdk-web-agent/releases" target="_blank" rel="noreferrer" className="underline">GitHub releases</a></li>
                                <li>Ejecuta el programa — se inicia en la bandeja del sistema</li>
                                <li>Presiona <strong>Reintentar</strong> cuando esté corriendo</li>
                            </ol>
                            <p className="text-xs text-amber-700">URL del agente: <code className="bg-amber-200 px-1 rounded">{agentWsUrl}</code></p>
                        </div>
                    )}

                    {intermediateMessages.length > 0 && isPending && (
                        <div className="bg-white/70 rounded-lg p-3 space-y-1">
                            {intermediateMessages.map((msg) => (
                                <p key={msg} className="text-xs text-gray-600 text-center">
                                    {msg}
                                </p>
                            ))}
                        </div>
                    )}

                    {status === "approved" && transactionDetails && (
                        <div className="bg-white/60 rounded-lg p-4 space-y-2 text-sm border border-green-200">
                            {transactionDetails.authorizationCode && (
                                <div className="flex justify-between">
                                    <span className="text-gray-600">Código autorización:</span>
                                    <span className="font-semibold">{transactionDetails.authorizationCode}</span>
                                </div>
                            )}
                            {transactionDetails.last4Digits != null && (
                                <div className="flex justify-between">
                                    <span className="text-gray-600">Tarjeta:</span>
                                    <span className="font-semibold">**** {transactionDetails.last4Digits}</span>
                                </div>
                            )}
                            {transactionDetails.cardType && (
                                <div className="flex justify-between">
                                    <span className="text-gray-600">Tipo:</span>
                                    <span className="font-semibold">
                                        {CARD_TYPES[transactionDetails.cardType] ?? transactionDetails.cardType}
                                    </span>
                                </div>
                            )}
                            {transactionDetails.cardBrand && (
                                <div className="flex justify-between">
                                    <span className="text-gray-600">Marca:</span>
                                    <span className="font-semibold">
                                        {CARD_BRANDS[transactionDetails.cardBrand] ?? transactionDetails.cardBrand}
                                    </span>
                                </div>
                            )}
                            {transactionDetails.operationNumber != null && (
                                <div className="flex justify-between">
                                    <span className="text-gray-600">N° operación:</span>
                                    <span className="font-semibold">{transactionDetails.operationNumber}</span>
                                </div>
                            )}
                        </div>
                    )}

                    <div className="text-center text-xs text-gray-400">
                        Terminal: {portName ?? "Sin configurar"} &bull; ID: {ticketId}
                    </div>

                    <div className="flex gap-3">
                        {isAgentOffline && (
                            <>
                                <Button onClick={handleCancel} variant="outline" className="flex-1">
                                    Cancelar
                                </Button>
                                <Button onClick={handleRetry} className="flex-1 bg-amber-600 hover:bg-amber-700">
                                    <RefreshCw className="w-4 h-4 mr-2" />
                                    Reintentar
                                </Button>
                            </>
                        )}
                        {isTerminal && (
                            <Button onClick={handleCancel} variant="outline" className="flex-1">
                                Cerrar
                            </Button>
                        )}
                        {isPending && (
                            <Button onClick={handleCancel} variant="destructive" className="flex-1">
                                Cancelar Pago
                            </Button>
                        )}
                        {["checking_agent", "connecting_agent", "opening_port", "polling"].includes(status) && (
                            <Button onClick={handleCancel} variant="outline" className="flex-1 text-gray-600">
                                Cancelar
                            </Button>
                        )}
                    </div>

                    {isPending && (
                        <div className="bg-blue-100 border border-blue-200 rounded-lg p-3 text-xs text-blue-900">
                            <p className="font-semibold mb-1">Instrucciones:</p>
                            <ul className="list-disc list-inside space-y-1">
                                <li>Inserte, deslice o acerque la tarjeta en el terminal</li>
                                <li>Seleccione el tipo de pago si lo solicita el terminal</li>
                                <li>Ingrese PIN si corresponde (tarjeta débito)</li>
                                <li>Espere la confirmación del banco</li>
                            </ul>
                        </div>
                    )}
                </CardContent>
            </Card>
        </div>
    );
}
