import { useState, useMemo, useRef, useEffect } from "react";
import { Chessboard } from "react-chessboard";
import { Chess } from "chess.js";
import type { GameUIProps } from "../registry";

interface ChessState {
    fen: string;
    players: { white: string; black: string };
    moveHistory: string[];
    status: string;
    winner: string | null;
}

// Chess.com-inspired board colors
const DARK_SQUARE = "#769656";
const LIGHT_SQUARE = "#eeeed2";
const LAST_MOVE_DARK = "#638a49";
const LAST_MOVE_LIGHT = "#cdd96e";
const SELECTED_SHADOW = "inset 0 0 0 4px rgba(20,85,30,0.8)";
const CHECK_BG = "rgba(220, 38, 38, 0.7)";

function Avatar({ username, color }: { username: string; color: "white" | "black" }) {
    return (
        <div
            className="w-8 h-8 rounded-sm flex items-center justify-center text-sm font-bold shrink-0"
            style={{
                backgroundColor: color === "white" ? "#f0d9b5" : "#2b1d0e",
                color: color === "white" ? "#2b1d0e" : "#f0d9b5",
                border: "2px solid rgba(255,255,255,0.15)",
            }}
        >
            {username?.[0]?.toUpperCase() ?? "?"}
        </div>
    );
}

function CapturedPieces({ fen, color }: { fen: string; color: "white" | "black" }) {
    const captured = useMemo(() => {
        const game = new Chess(fen);
        const board = game.board();
        const counts: Record<string, number> = { p: 0, n: 0, b: 0, r: 0, q: 0 };
        for (const row of board) {
            for (const sq of row) {
                if (sq) counts[sq.type] = (counts[sq.type] ?? 0) + 1;
            }
        }
        const start: Record<string, number> = { p: 8, n: 2, b: 2, r: 2, q: 1 };
        const pieceSymbols: Record<string, string> = {
            p: color === "white" ? "♟" : "♙",
            n: color === "white" ? "♞" : "♘",
            b: color === "white" ? "♝" : "♗",
            r: color === "white" ? "♜" : "♖",
            q: color === "white" ? "♛" : "♕",
        };
        const pieceColor = color === "white" ? "b" : "w";
        const result: string[] = [];
        for (const [type, symbol] of Object.entries(pieceSymbols)) {
            const remaining = board.flat().filter(s => s?.type === type && s.color === pieceColor).length;
            const missing = start[type]! - remaining;
            for (let i = 0; i < missing; i++) result.push(symbol);
        }
        return result;
    }, [fen, color]);

    if (captured.length === 0) return null;
    return (
        <span className="text-sm opacity-70 leading-none tracking-tight">{captured.join("")}</span>
    );
}

function PlayerPanel({
    username,
    color,
    isActive,
    fen,
    isTop,
}: {
    username: string;
    color: "white" | "black";
    isActive: boolean;
    fen: string;
    isTop: boolean;
}) {
    return (
        <div
            className="flex items-center gap-2.5 px-3 py-2 rounded-sm select-none"
            style={{
                backgroundColor: "#262421",
                borderTop: isTop ? undefined : "2px solid #1a1917",
                borderBottom: isTop ? "2px solid #1a1917" : undefined,
            }}
        >
            <Avatar username={username} color={color} />
            <div className="flex flex-col gap-0.5 min-w-0">
                <span className="text-sm font-semibold leading-none truncate" style={{ color: "#f0d9b5" }}>
                    {username}
                </span>
                <div className="flex items-center gap-1.5">
                    <span className="text-[11px] opacity-50 leading-none capitalize" style={{ color: "#8e8984" }}>
                        {color}
                    </span>
                    <CapturedPieces fen={fen} color={color === "white" ? "black" : "white"} />
                </div>
            </div>
            {isActive && (
                <div className="ml-auto flex items-center gap-1.5">
                    <span
                        className="w-2 h-2 rounded-full animate-pulse"
                        style={{ backgroundColor: "#81b64c" }}
                    />
                    <span className="text-[11px] font-medium" style={{ color: "#81b64c" }}>
                        Your turn
                    </span>
                </div>
            )}
        </div>
    );
}

function MoveHistory({ moveHistory }: { moveHistory: string[] }) {
    const ref = useRef<HTMLDivElement>(null);
    useEffect(() => {
        if (ref.current) ref.current.scrollTop = ref.current.scrollHeight;
    }, [moveHistory.length]);

    const pairs: [string, string | undefined][] = [];
    for (let i = 0; i < moveHistory.length; i += 2) {
        pairs.push([moveHistory[i]!, moveHistory[i + 1]]);
    }

    return (
        <div className="flex flex-col h-full" style={{ backgroundColor: "#262421" }}>
            <div
                className="px-3 py-2 text-xs font-semibold uppercase tracking-wider border-b"
                style={{ color: "#8e8984", borderColor: "#1a1917" }}
            >
                Moves
            </div>
            <div ref={ref} className="flex-1 overflow-y-auto" style={{ maxHeight: "360px" }}>
                {pairs.length === 0 ? (
                    <div className="px-3 py-3 text-xs" style={{ color: "#6e6966" }}>
                        No moves yet
                    </div>
                ) : (
                    <table className="w-full text-xs font-mono">
                        <tbody>
                            {pairs.map(([white, black], i) => (
                                <tr
                                    key={i}
                                    style={{
                                        backgroundColor: i % 2 === 0 ? "transparent" : "rgba(255,255,255,0.03)",
                                    }}
                                >
                                    <td
                                        className="pl-3 pr-2 py-1 select-none w-8 text-right"
                                        style={{ color: "#6e6966" }}
                                    >
                                        {i + 1}.
                                    </td>
                                    <td
                                        className="px-2 py-1 w-16 font-medium"
                                        style={{ color: "#f0d9b5" }}
                                    >
                                        {white}
                                    </td>
                                    <td
                                        className="px-2 py-1 w-16"
                                        style={{ color: black ? "#f0d9b5" : "transparent" }}
                                    >
                                        {black ?? "—"}
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                )}
            </div>
        </div>
    );
}

function GameOverOverlay({
    status,
    winner,
    myPlayerId,
    players,
}: {
    status: string;
    winner: string | null;
    myPlayerId: string;
    players: { discordId: string; username: string }[];
}) {
    const winnerName = winner ? (players.find(p => p.discordId === winner)?.username ?? winner) : null;
    const isWinner = winner === myPlayerId;
    const isDraw = !winner;

    let title = "";
    let subtitle = "";
    let titleColor = "#f0d9b5";

    if (isDraw) {
        title = "Draw";
        subtitle = status === "stalemate" ? "Stalemate" : "Game drawn";
        titleColor = "#8e8984";
    } else if (isWinner) {
        title = "You Win!";
        subtitle = status === "forfeit" ? "Opponent forfeited" : "By checkmate";
        titleColor = "#81b64c";
    } else {
        title = "You Lose";
        subtitle =
            status === "forfeit"
                ? "You forfeited"
                : status === "checkmate"
                ? `${winnerName} wins by checkmate`
                : `${winnerName} wins`;
        titleColor = "#c84b4b";
    }

    return (
        <div
            className="absolute inset-0 flex flex-col items-center justify-center z-10 rounded-sm"
            style={{ backgroundColor: "rgba(20, 18, 15, 0.82)", backdropFilter: "blur(2px)" }}
        >
            <div
                className="flex flex-col items-center gap-2 px-8 py-6 rounded-lg"
                style={{ backgroundColor: "#1a1917", border: "1px solid #3a3733" }}
            >
                <div className="text-3xl font-bold" style={{ color: titleColor }}>
                    {title}
                </div>
                <div className="text-sm" style={{ color: "#8e8984" }}>
                    {subtitle}
                </div>
            </div>
        </div>
    );
}

export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players }: GameUIProps) {
    const chess = state as ChessState;
    const [promotionFrom, setPromotionFrom] = useState<string | null>(null);
    const [promotionTo, setPromotionTo] = useState<string | null>(null);
    const [selectedSquare, setSelectedSquare] = useState<string | null>(null);
    const [confirmForfeit, setConfirmForfeit] = useState(false);
    const containerRef = useRef<HTMLDivElement>(null);
    const [boardWidth, setBoardWidth] = useState(480);

    // Optimistic local FEN — updated immediately on drag/click, then confirmed by server.
    // We track a local move count so we never let a stale server message roll back the board.
    const [localFen, setLocalFen] = useState<string>(() => chess?.fen ?? "start");
    const localFenRef = useRef<string>(localFen);
    const localMoveCountRef = useRef<number>(chess?.moveHistory?.length ?? 0);
    const lastMoveRef = useRef<{ from: string; to: string } | null>(null);

    // Sync local FEN from server — only if server has caught up to our optimistic position.
    // This prevents any late/duplicate GAME_STARTED messages from rolling back the board.
    useEffect(() => {
        if (!chess?.fen) return;
        const serverMoves = chess.moveHistory?.length ?? 0;
        if (serverMoves >= localMoveCountRef.current) {
            localMoveCountRef.current = serverMoves;
            localFenRef.current = chess.fen;
            setLocalFen(chess.fen);
        }
    }, [chess?.fen, chess?.moveHistory?.length]);

    // Responsive board sizing
    useEffect(() => {
        const container = containerRef.current;
        if (!container) return;
        const observer = new ResizeObserver((entries) => {
            const w = entries[0]?.contentRect.width ?? 480;
            setBoardWidth(Math.max(280, Math.min(520, w)));
        });
        observer.observe(container);
        return () => observer.disconnect();
    }, []);

    const game = useMemo(() => {
        if (!localFen || localFen === "start") return new Chess();
        try { return new Chess(localFen); } catch { return new Chess(); }
    }, [localFen]);

    if (!chess?.players) {
        return (
            <div className="flex items-center justify-center p-8 text-sm" style={{ color: "#8e8984" }}>
                Waiting for game to start…
            </div>
        );
    }

    const isWhite = chess.players.white === myPlayerId;
    const isBlack = chess.players.black === myPlayerId;
    const isBothSides = isWhite && isBlack;
    const myColor = isWhite ? "white" : isBlack ? "black" : null;
    const turn = game.turn() === "w" ? "white" : "black";
    const isMyTurn = (isBothSides || myColor === turn) && !isSpectator;
    const boardOrientation = myColor ?? "white";
    const isGameOver = chess.status !== "playing";

    const topColor = boardOrientation === "white" ? "black" : "white";
    const bottomColor = boardOrientation;

    const topPlayerId = chess.players[topColor];
    const bottomPlayerId = chess.players[bottomColor];
    const topPlayer = players.find(p => p.discordId === topPlayerId);
    const bottomPlayer = players.find(p => p.discordId === bottomPlayerId);

    const isTopActive = !isGameOver && turn === topColor && !isSpectator;
    const isBottomActive = !isGameOver && turn === bottomColor && !isSpectator;

    function dispatchMove(from: string, to: string, promotion?: string) {
        try {
            const optimistic = new Chess(localFenRef.current);
            const moved = optimistic.move({ from, to, promotion: promotion ?? "q" });
            if (moved) {
                localMoveCountRef.current += 1;
                localFenRef.current = optimistic.fen();
                setLocalFen(optimistic.fen());
            }
        } catch { /* invalid — server will reject */ }
        lastMoveRef.current = { from, to };
        setSelectedSquare(null);
        onAction({ type: "move", from, to, ...(promotion ? { promotion } : {}) });
    }

    function onDrop(sourceSquare: string, targetSquare: string): boolean {
        if (isSpectator || !isMyTurn || isGameOver) return false;
        const testGame = new Chess(localFenRef.current);
        const piece = testGame.get(sourceSquare as any);
        if (piece?.type === "p") {
            const rank = targetSquare[1];
            if ((piece.color === "w" && rank === "8") || (piece.color === "b" && rank === "1")) {
                setPromotionFrom(sourceSquare);
                setPromotionTo(targetSquare);
                lastMoveRef.current = { from: sourceSquare, to: targetSquare };
                return true;
            }
        }
        let move;
        try { move = testGame.move({ from: sourceSquare, to: targetSquare }); } catch { return false; }
        if (!move) return false;
        dispatchMove(sourceSquare, targetSquare);
        return true;
    }

    function handlePromotion(piece: string) {
        if (promotionFrom && promotionTo) {
            const promotionPiece = piece[1]?.toLowerCase() ?? "q";
            dispatchMove(promotionFrom, promotionTo, promotionPiece);
        }
        setPromotionFrom(null);
        setPromotionTo(null);
        return true;
    }

    function onSquareClick(square: string) {
        if (isSpectator || isGameOver || !isMyTurn) return;
        if (promotionFrom !== null) return;
        const testGame = new Chess(localFenRef.current);

        if (selectedSquare !== null) {
            if (square === selectedSquare) { setSelectedSquare(null); return; }
            const legalMoves = testGame.moves({ square: selectedSquare as any, verbose: true });
            const validDest = legalMoves.find(m => m.to === square);
            if (validDest) {
                const piece = testGame.get(selectedSquare as any);
                if (piece?.type === "p") {
                    const rank = square[1];
                    if ((piece.color === "w" && rank === "8") || (piece.color === "b" && rank === "1")) {
                        setPromotionFrom(selectedSquare);
                        setPromotionTo(square);
                        lastMoveRef.current = { from: selectedSquare, to: square };
                        setSelectedSquare(null);
                        return;
                    }
                }
                dispatchMove(selectedSquare, square);
                return;
            }
            const clicked = testGame.get(square as any);
            if (clicked) {
                const color = clicked.color === "w" ? "white" : "black";
                if (isBothSides ? color === turn : color === myColor) {
                    setSelectedSquare(square);
                    return;
                }
            }
            setSelectedSquare(null);
            return;
        }

        const clicked = testGame.get(square as any);
        if (!clicked) return;
        const color = clicked.color === "w" ? "white" : "black";
        if (isBothSides ? color === turn : color === myColor) setSelectedSquare(square);
    }

    function isDraggablePiece({ piece }: { piece: string }): boolean {
        if (isSpectator || !isMyTurn || isGameOver) return false;
        const pieceColor = piece[0] === "w" ? "white" : "black";
        return isBothSides ? pieceColor === turn : pieceColor === myColor;
    }

    // Square styles
    const customSquareStyles: Record<string, React.CSSProperties> = {};

    const lastMove = lastMoveRef.current;
    if (lastMove) {
        const isDarkSquare = (sq: string) => {
            const f = sq.charCodeAt(0) - 97;
            const r = parseInt(sq[1]!) - 1;
            return (f + r) % 2 === 0;
        };
        customSquareStyles[lastMove.from] = {
            backgroundColor: isDarkSquare(lastMove.from) ? LAST_MOVE_DARK : LAST_MOVE_LIGHT,
        };
        customSquareStyles[lastMove.to] = {
            backgroundColor: isDarkSquare(lastMove.to) ? LAST_MOVE_DARK : LAST_MOVE_LIGHT,
        };
    }

    if (selectedSquare !== null) {
        customSquareStyles[selectedSquare] = {
            ...customSquareStyles[selectedSquare],
            boxShadow: SELECTED_SHADOW,
        };
        const legalMoves = game.moves({ square: selectedSquare as any, verbose: true });
        for (const m of legalMoves) {
            const hasPiece = game.get(m.to as any) !== null;
            customSquareStyles[m.to] = {
                ...customSquareStyles[m.to],
                background: hasPiece
                    ? `radial-gradient(circle, rgba(20,85,30,0.4) 75%, transparent 77%)`
                    : `radial-gradient(circle, rgba(20,85,30,0.45) 28%, transparent 30%)`,
            };
        }
    }

    if (game.inCheck()) {
        const board = game.board();
        const kingColor = game.turn();
        for (let r = 0; r < 8; r++) {
            for (let c = 0; c < 8; c++) {
                const sq = board[r][c];
                if (sq?.type === "k" && sq.color === kingColor) {
                    const key = `${String.fromCharCode(97 + c)}${8 - r}`;
                    customSquareStyles[key] = {
                        ...customSquareStyles[key],
                        background: `radial-gradient(ellipse at center, ${CHECK_BG} 0%, rgba(220,38,38,0.4) 50%, transparent 75%)`,
                    };
                }
            }
        }
    }

    return (
        <div className="flex flex-col lg:flex-row gap-0 items-start justify-center">
            {/* Board column */}
            <div
                className="flex flex-col rounded-sm overflow-hidden shadow-2xl"
                style={{ backgroundColor: "#262421" }}
            >
                {/* Opponent panel */}
                <PlayerPanel
                    username={topPlayer?.username ?? (isSpectator ? "Player" : "Opponent")}
                    color={topColor}
                    isActive={isTopActive}
                    fen={localFen}
                    isTop
                />

                {/* Board wrapper */}
                <div ref={containerRef} className="relative" style={{ lineHeight: 0 }}>
                    <Chessboard
                        position={localFen}
                        onPieceDrop={onDrop}
                        onPromotionPieceSelect={handlePromotion}
                        onSquareClick={onSquareClick}
                        boardOrientation={boardOrientation}
                        isDraggablePiece={isDraggablePiece}
                        boardWidth={boardWidth}
                        showPromotionDialog={promotionFrom !== null}
                        promotionToSquare={promotionTo as any}
                        animationDuration={150}
                        customSquareStyles={customSquareStyles}
                        customDarkSquareStyle={{ backgroundColor: DARK_SQUARE }}
                        customLightSquareStyle={{ backgroundColor: LIGHT_SQUARE }}
                        customBoardStyle={{ borderRadius: "0" }}
                        customDropSquareStyle={{ boxShadow: "inset 0 0 1px 6px rgba(20,85,30,0.7)" }}
                        customPremoveDarkSquareStyle={{ backgroundColor: "#a04a4a" }}
                        customPremoveLightSquareStyle={{ backgroundColor: "#d08080" }}
                    />
                    {isGameOver && (
                        <GameOverOverlay
                            status={chess.status}
                            winner={chess.winner}
                            myPlayerId={myPlayerId}
                            players={players}
                        />
                    )}
                </div>

                {/* My panel */}
                <PlayerPanel
                    username={bottomPlayer?.username ?? (isSpectator ? "Spectator" : "You")}
                    color={bottomColor}
                    isActive={isBottomActive}
                    fen={localFen}
                    isTop={false}
                />
            </div>

            {/* Sidebar */}
            <div
                className="flex flex-col lg:w-52 w-full rounded-sm overflow-hidden shadow-2xl lg:ml-2 mt-2 lg:mt-0"
                style={{
                    backgroundColor: "#262421",
                    border: "1px solid #1a1917",
                    minHeight: "200px",
                    alignSelf: "stretch",
                }}
            >
                <MoveHistory moveHistory={chess.moveHistory ?? []} />

                {!isSpectator && chess.status === "playing" && (
                    <div className="p-3 border-t" style={{ borderColor: "#1a1917" }}>
                        {confirmForfeit ? (
                            <div className="flex gap-2">
                                <button
                                    onClick={() => {
                                        onAction({ type: "forfeit" });
                                        setConfirmForfeit(false);
                                    }}
                                    className="flex-1 rounded px-3 py-2 text-xs font-semibold transition-colors"
                                    style={{
                                        backgroundColor: "rgba(180,40,40,0.2)",
                                        color: "#e06060",
                                        border: "1px solid rgba(180,40,40,0.4)",
                                    }}
                                >
                                    Confirm
                                </button>
                                <button
                                    onClick={() => setConfirmForfeit(false)}
                                    className="rounded px-3 py-2 text-xs font-semibold transition-colors"
                                    style={{
                                        backgroundColor: "rgba(255,255,255,0.05)",
                                        color: "#8e8984",
                                        border: "1px solid #3a3733",
                                    }}
                                >
                                    Cancel
                                </button>
                            </div>
                        ) : (
                            <button
                                onClick={() => setConfirmForfeit(true)}
                                className="w-full rounded px-3 py-2 text-xs font-semibold transition-opacity hover:opacity-80"
                                style={{
                                    backgroundColor: "rgba(255,255,255,0.05)",
                                    color: "#8e8984",
                                    border: "1px solid #3a3733",
                                }}
                            >
                                Resign
                            </button>
                        )}
                    </div>
                )}
            </div>
        </div>
    );
}
