"use client";

import { useState, useEffect, useCallback, useRef, useMemo } from "react";
import { ZipPuzzle, canMove } from "@/lib/generators/zip";
import WinBanner from "./WinBanner";

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

const WALL_W = 5;
const PATH_COLOR = "#f97316";   // orange — matches LinkedIn
const PATH_DONE  = "#10b981";   // green on win
const PATH_BG    = "#fde8d0";   // light salmon for path cells
const CELL_1_BG  = "#fddcbb";   // slightly deeper salmon for waypoint 1 cell

const STORAGE_KEY = (d: string) => `zip-${d}`;
function cellKey(r: number, c: number) { return `${r},${c}`; }

const MAX_CELL = 52;

export default function ZipBoard({ puzzle, date, onSolve }: Props) {
  const { size, path: solution, numberedCells, walls } = puzzle;
  const totalCells = size * size;
  const [CELL, setCELL] = useState(() =>
    typeof window === "undefined" ? MAX_CELL : Math.min(MAX_CELL, Math.floor((window.innerWidth - 32) / size))
  );
  const STEP = CELL;

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

  const pathHistory = useRef<[number, number][][]>([]);
  const [dragging, setDragging] = useState(false);
  const [won, setWon] = useState(false);
  const [elapsed, setElapsed] = useState(0);
  const [t0] = useState(() => Date.now());
  const boardRef = useRef<HTMLDivElement>(null);

  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]);

  const checkWin = useCallback((p: [number, number][]) => {
    if (p.length !== totalCells) return false;
    const waypointCells = Object.entries(numberedCells).sort((a, b) => a[1] - b[1]).map(([k]) => k);
    let wi = 0;
    for (const [r, c] of p) {
      if (wi < waypointCells.length && cellKey(r, c) === waypointCells[wi]) wi++;
    }
    return wi === waypointCells.length;
  }, [totalCells, numberedCells]);

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

  const fmt = (s: number) => `${String(Math.floor(s / 60)).padStart(2, "0")}:${String(s % 60).padStart(2, "0")}`;

  const pathSet = new Set(userPath.map(([r, c]) => cellKey(r, c)));

  function getCellFromPoint(clientX: number, clientY: number): [number, number] | null {
    const board = boardRef.current;
    if (!board) return null;
    const rect = board.getBoundingClientRect();
    const c = Math.floor((clientX - rect.left) / STEP);
    const r = Math.floor((clientY - rect.top) / STEP);
    if (r < 0 || r >= size || c < 0 || c >= size) return null;
    return [r, c];
  }

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

  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === "z") { e.preventDefault(); undo(); }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [undo]);

  const startPath = useCallback((r: number, c: number) => {
    if (won) return;
    setDragging(true);
    const key = numberedCells[cellKey(r, c)];
    if (key === 1) {
      pathHistory.current.push([...userPath]);
      setUserPath([[r, c]]);
      return;
    }
    const last = userPath[userPath.length - 1];
    if (last && last[0] === r && last[1] === c) return;
    if (key) {
      pathHistory.current.push([...userPath]);
      setUserPath([[r, c]]);
    }
  }, [won, numberedCells, userPath]);

  const extendPath = useCallback((r: number, c: number) => {
    if (!dragging || won) return;
    setUserPath(prev => {
      if (!prev.length) return prev;
      const last = prev[prev.length - 1];
      const key = cellKey(r, c);
      const dr = Math.abs(last[0] - r), dc = Math.abs(last[1] - c);
      if (dr + dc !== 1) return prev;
      if (!canMove(walls, last[0], last[1], r, c)) return prev;
      if (prev.length >= 2 && prev[prev.length - 2][0] === r && prev[prev.length - 2][1] === c)
        return prev.slice(0, -1);
      if (pathSet.has(key)) return prev;
      return [...prev, [r, c]];
    });
  }, [dragging, won, pathSet, walls]);

  const handleMouseDown = (e: React.MouseEvent, r: number, c: number) => {
    e.preventDefault(); startPath(r, c);
  };
  const handleMouseMove = (e: React.MouseEvent) => {
    if (!dragging) return;
    const cell = getCellFromPoint(e.clientX, e.clientY);
    if (cell) extendPath(cell[0], cell[1]);
  };
  const handleTouchStart = (e: React.TouchEvent, r: number, c: number) => {
    e.preventDefault(); startPath(r, c);
  };
  const handleTouchMove = (e: React.TouchEvent) => {
    if (!dragging) return;
    const t = e.touches[0];
    const cell = getCellFromPoint(t.clientX, t.clientY);
    if (cell) extendPath(cell[0], cell[1]);
  };

  // Thick orange polyline with rounded joins — matches LinkedIn visual
  function renderPath() {
    if (userPath.length < 1) return null;
    const color = won ? PATH_DONE : PATH_COLOR;
    const pts = userPath.map(([r, c]) => `${c * STEP + CELL / 2},${r * STEP + CELL / 2}`).join(" ");
    return (
      <svg
        style={{ position: "absolute", inset: 0, pointerEvents: "none", zIndex: 5 }}
        width={size * STEP} height={size * STEP}
      >
        <polyline
          points={pts}
          stroke={color}
          strokeWidth={CELL * 0.46}
          strokeLinecap="round"
          strokeLinejoin="round"
          fill="none"
          opacity={0.85}
        />
      </svg>
    );
  }

  const handleHint = () => {
    if (won) return;
    let matchLen = 0;
    for (let i = 0; i < Math.min(userPath.length, solution.length); i++) {
      if (userPath[i][0] === solution[i][0] && userPath[i][1] === solution[i][1]) matchLen = i + 1;
      else break;
    }
    if (matchLen < solution.length)
      setUserPath(solution.slice(0, matchLen + 1) as [number, number][]);
  };

  const reset = () => { pathHistory.current = []; setUserPath([]); setWon(false); };

  const boardSize = size * STEP;
  const waypointR = Math.round(CELL * 0.35);   // radius of black circle

  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>{userPath.length} / {totalCells}</span>
        <span className="tabular-nums">{fmt(elapsed)}</span>
      </div>

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

      <div
        ref={boardRef}
        style={{
          position: "relative", width: boardSize, height: boardSize,
          userSelect: "none", touchAction: "none",
          borderRadius: 8, overflow: "hidden",
          border: "1.5px solid #d1d5db",
          background: "#ffffff",
        }}
        onMouseMove={handleMouseMove}
        onMouseUp={() => setDragging(false)}
        onMouseLeave={() => setDragging(false)}
        onTouchMove={handleTouchMove}
        onTouchEnd={() => setDragging(false)}
      >
        {renderPath()}

        {Array.from({ length: size }, (_, r) =>
          Array.from({ length: size }, (_, c) => {
            const key = cellKey(r, c);
            const inPath = pathSet.has(key);
            const num = numberedCells[key];
            const w = walls[r][c];
            const isStart = num === 1;

            const bTop    = (w & 8) ? `${WALL_W}px solid #1a1a1a` : "1px solid #e5e7eb";
            const bBottom = (w & 2) ? `${WALL_W}px solid #1a1a1a` : "1px solid #e5e7eb";
            const bLeft   = (w & 4) ? `${WALL_W}px solid #1a1a1a` : "1px solid #e5e7eb";
            const bRight  = (w & 1) ? `${WALL_W}px solid #1a1a1a` : "1px solid #e5e7eb";

            let bg = "#ffffff";
            if (inPath) bg = won ? "#d1fae5" : PATH_BG;
            else if (isStart) bg = CELL_1_BG;

            return (
              <div
                key={key}
                onMouseDown={e => handleMouseDown(e, r, c)}
                onTouchStart={e => handleTouchStart(e, r, c)}
                style={{
                  position: "absolute",
                  left: c * STEP, top: r * STEP,
                  width: CELL, height: CELL,
                  backgroundColor: bg,
                  borderTop: bTop, borderBottom: bBottom,
                  borderLeft: bLeft, borderRight: bRight,
                  boxSizing: "border-box",
                  display: "flex", alignItems: "center", justifyContent: "center",
                  cursor: "crosshair",
                  zIndex: num ? 10 : 2,
                  transition: "background-color 0.08s",
                }}
              >
                {num && (
                  <div style={{
                    width: waypointR * 2,
                    height: waypointR * 2,
                    borderRadius: "50%",
                    background: "#1a1a1a",
                    display: "flex", alignItems: "center", justifyContent: "center",
                    color: "#ffffff",
                    fontSize: CELL * 0.28,
                    fontWeight: 700,
                    zIndex: 20,
                    position: "relative",
                    flexShrink: 0,
                  }}>{num}</div>
                )}
              </div>
            );
          })
        )}
      </div>

      <div className="flex gap-3">
        {!won && (
          <>
            <button
              onClick={undo}
              disabled={pathHistory.current.length === 0}
              className="px-5 py-2 rounded-full border border-gray-300 text-gray-500 hover:bg-gray-50 text-sm transition-colors disabled:opacity-30"
              title="Annuler (Ctrl+Z)"
            >
              ↺ Annuler
            </button>
            <button onClick={reset}
              className="px-5 py-2 rounded-full border border-gray-300 text-gray-500 hover:bg-gray-50 text-sm transition-colors">
              Recommencer
            </button>
            <button onClick={handleHint}
              className="px-5 py-2 rounded-full border border-gray-900 text-gray-900 hover:bg-gray-50 text-sm font-medium transition-colors">
              Indice
            </button>
          </>
        )}
      </div>

      <p className="text-xs text-gray-400 text-center max-w-xs">
        Glissez du <b>1</b> en passant par les chiffres dans l&apos;ordre, en couvrant toutes les cases.
      </p>
    </div>
  );
}
