"use client";

import { useState, useEffect, useCallback, useRef } from "react";
import { SudokuPuzzle } from "@/lib/generators/sudoku";
import WinBanner from "./WinBanner";

interface Props {
  puzzle: SudokuPuzzle;
  date: string;
  onSolve?: (elapsed: number) => void;
}

const MAX_CELL = 64;
const STORAGE_KEY = (d: string) => `sudoku-${d}`;
const DIAGONAL_ERROR = "repeating-linear-gradient(-45deg, rgba(220,38,38,0.55) 0px, rgba(220,38,38,0.55) 3px, rgba(220,38,38,0.2) 3px, rgba(220,38,38,0.2) 6px)";

function checkWin(grid: number[][], solution: number[][]): boolean {
  for (let r = 0; r < 6; r++)
    for (let c = 0; c < 6; c++)
      if (grid[r][c] !== solution[r][c]) return false;
  return true;
}

function getErrors(grid: number[][], given: number[][]): Set<string> {
  const errors = new Set<string>();
  for (let r = 0; r < 6; r++) {
    for (let c = 0; c < 6; c++) {
      const v = grid[r][c];
      if (!v || given[r][c]) continue;
      // Row
      for (let cc = 0; cc < 6; cc++) if (cc !== c && grid[r][cc] === v) { errors.add(`${r},${c}`); errors.add(`${r},${cc}`); }
      // Col
      for (let rr = 0; rr < 6; rr++) if (rr !== r && grid[rr][c] === v) { errors.add(`${r},${c}`); errors.add(`${rr},${c}`); }
      // Box
      const br = Math.floor(r / 2) * 2, bc = Math.floor(c / 3) * 3;
      for (let dr = 0; dr < 2; dr++)
        for (let dc = 0; dc < 3; dc++) {
          const rr = br + dr, cc = bc + dc;
          if ((rr !== r || cc !== c) && grid[rr][cc] === v) { errors.add(`${r},${c}`); errors.add(`${rr},${cc}`); }
        }
    }
  }
  return errors;
}

export default function SudokuBoard({ puzzle, date, onSolve }: Props) {
  const { given, solution } = puzzle;
  const size = 6;
  const [CELL, setCELL] = useState(() =>
    typeof window === "undefined" ? MAX_CELL : Math.min(MAX_CELL, Math.floor((window.innerWidth - 32) / size))
  );

  const [grid, setGrid] = useState<number[][]>(() => {
    if (typeof window !== "undefined") {
      const s = localStorage.getItem(STORAGE_KEY(date));
      if (s) return JSON.parse(s);
    }
    return given.map(r => [...r]);
  });

  const [selected, setSelected] = useState<[number, number] | null>(null);
  const [won, setWon] = useState(false);
  const [elapsed, setElapsed] = useState(0);
  const [t0] = useState(() => Date.now());
  const history = useRef<number[][][]>([]);

  useEffect(() => {
    const update = () => setCELL(Math.min(MAX_CELL, Math.floor((window.innerWidth - 32) / size)));
    window.addEventListener("resize", update);
    return () => window.removeEventListener("resize", update);
  }, [size]);

  useEffect(() => {
    if (won) return;
    const id = setInterval(() => setElapsed(Math.floor((Date.now() - t0) / 1000)), 500);
    return () => clearInterval(id);
  }, [won, t0]);

  useEffect(() => {
    localStorage.setItem(STORAGE_KEY(date), JSON.stringify(grid));
    if (!won && checkWin(grid, solution)) { setWon(true); onSolve?.(Math.floor((Date.now() - t0) / 1000)); }
  }, [grid, date, solution, won, onSolve]);

  const errors = won ? new Set<string>() : getErrors(grid, given);
  const filled = grid.flat().filter(Boolean).length;
  const fmt = (s: number) => `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`;

  const input = useCallback((val: number) => {
    if (!selected || won) return;
    const [r, c] = selected;
    if (given[r][c]) return;
    setGrid(prev => {
      history.current.push(prev.map(row => [...row]));
      const next = prev.map(row => [...row]);
      next[r][c] = next[r][c] === val ? 0 : val;
      return next;
    });
  }, [selected, won, given]);

  const undo = useCallback(() => {
    if (won || history.current.length === 0) return;
    const prev = history.current.pop()!;
    setGrid(prev);
  }, [won]);

  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      const n = parseInt(e.key);
      if (n >= 1 && n <= 6) input(n);
      if (e.key === "Backspace" || e.key === "Delete" || e.key === "0") input(0);
      if ((e.ctrlKey || e.metaKey) && e.key === "z") undo();
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [input, undo]);

  const reset = () => { history.current = []; setGrid(given.map(r => [...r])); setSelected(null); setWon(false); };

  const handleHint = useCallback(() => {
    if (won) return;
    // Find first empty non-given cell
    for (let r = 0; r < 6; r++)
      for (let c = 0; c < 6; c++)
        if (!given[r][c] && grid[r][c] === 0) {
          history.current.push(grid.map(row => [...row]));
          setGrid(prev => {
            const next = prev.map(row => [...row]);
            next[r][c] = solution[r][c];
            return next;
          });
          setSelected([r, c]);
          return;
        }
  }, [won, given, grid, solution]);

  const [selR, selC] = selected ?? [-1, -1];

  // Box borders: thick between 2x3 boxes
  const boxBorderB = (r: number) => (r === 1 || r === 3) ? "3px solid #1a1a1a" : "1px solid #d1d5db";
  const boxBorderR = (c: number) => (c === 2) ? "3px solid #1a1a1a" : "1px solid #d1d5db";

  return (
    <div className="flex flex-col items-center gap-4">
      <div className="flex items-center gap-8 text-sm text-gray-500 font-medium">
        <span>{filled} / 36</span>
        <span className="tabular-nums">{fmt(elapsed)}</span>
      </div>

      {won && <WinBanner game="sudoku" date={date} elapsed={elapsed} />}

      {/* Grid */}
      <div style={{ border: "3px solid #1a1a1a", display: "inline-block", borderRadius: 4 }}>
        {Array.from({ length: 6 }, (_, r) => (
          <div key={r} style={{ display: "flex" }}>
            {Array.from({ length: 6 }, (_, c) => {
              const val = grid[r][c];
              const isGiven = !!given[r][c];
              const isSelected = r === selR && c === selC;
              const isSameVal = selected && val && grid[selR]?.[selC] === val && !isSelected;
              const isHighlighted = selected && !isSelected && (r === selR || c === selC || (Math.floor(r / 2) === Math.floor(selR / 2) && Math.floor(c / 3) === Math.floor(selC / 3)));
              const err = errors.has(`${r},${c}`);

              let bg = "#ffffff";
              const bgImage: string | undefined = err ? DIAGONAL_ERROR : undefined;
              if (isSelected) bg = "#ccfbf1";
              else if (isSameVal) bg = "#99f6e4";
              else if (isHighlighted) bg = "#f0fdfa";

              const selectedBorder = isSelected ? "2px solid #0d9488" : undefined;

              return (
                <div
                  key={c}
                  onClick={() => !won && setSelected([r, c])}
                  style={{
                    width: CELL,
                    height: CELL,
                    backgroundColor: bg,
                    backgroundImage: bgImage,
                    borderBottom: selectedBorder ?? boxBorderB(r),
                    borderRight: selectedBorder ?? boxBorderR(c),
                    borderTop: isSelected ? "2px solid #10b981" : undefined,
                    borderLeft: isSelected ? "2px solid #10b981" : undefined,
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    cursor: isGiven || won ? "default" : "pointer",
                    fontSize: CELL * 0.42,
                    fontWeight: isGiven ? 700 : 500,
                    color: err ? "#dc2626" : isGiven ? "#1a1a1a" : "#1d4ed8",
                    transition: "background-color 0.1s",
                    userSelect: "none",
                    position: "relative",
                    zIndex: isSelected ? 1 : 0,
                    boxSizing: "border-box",
                  }}
                >
                  {val || ""}
                </div>
              );
            })}
          </div>
        ))}
      </div>

      {/* Number pad */}
      {!won && (
        <div className="flex gap-2">
          {[1, 2, 3, 4, 5, 6].map(n => (
            <button
              key={n}
              onClick={() => input(n)}
              className="w-10 h-10 rounded-lg border border-gray-300 text-gray-700 font-semibold text-base hover:bg-blue-50 hover:border-blue-300 transition-colors"
            >
              {n}
            </button>
          ))}
          <button
            onClick={() => input(0)}
            className="w-10 h-10 rounded-lg border border-gray-200 text-gray-400 text-xs hover:bg-gray-50 transition-colors"
            title="Effacer"
          >
            ✕
          </button>
          <button
            onClick={undo}
            disabled={history.current.length === 0}
            className="w-10 h-10 rounded-lg border border-gray-200 text-gray-400 text-base hover:bg-gray-50 transition-colors disabled:opacity-30"
            title="Annuler (Ctrl+Z)"
          >
            ↺
          </button>
        </div>
      )}

      <p className="text-xs text-gray-400 text-center max-w-[300px]">
        Chiffres 1–6 : un seul par ligne, colonne et bloc 2×3. Clic + clavier ou pavé numérique.
      </p>

      <div className="flex gap-3">
        {!won && (
          <button onClick={handleHint}
            className="px-4 py-2 rounded-xl border border-amber-200 text-amber-600 hover:bg-amber-50 text-sm transition-colors">
            Indice
          </button>
        )}
        <button onClick={reset} className="px-4 py-2 rounded-xl border border-gray-200 text-gray-500 hover:bg-gray-50 text-sm transition-colors">
          Recommencer
        </button>
      </div>
    </div>
  );
}
