import { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useGameStore } from '../store/gameStore';
import { emit } from '../lib/socket';
import { leaveGame } from '../lib/leaveGame';
import { computePlayable, stashWinner } from '../lib/gameRules';
import { computeTotal } from '../lib/standings';
import { useIsDesktop } from '../lib/useIsDesktop';
import { useFitScale } from '../lib/useFitScale';
import Hand from '../components/Hand';
import GuessControls from '../components/GuessControls';
import Trick from '../components/Trick';
import Standings from '../components/Standings';
import PlayerCircle from '../components/PlayerCircle';
import FaceDownCards from '../components/FaceDownCards';
import GameOver from './GameOver';
import type { PlayerInfo, StashData } from '../types';

// A completed trick stays face-up for SETTLE_MS (so the last card visibly joins
// the pile), then is swept towards the winner over COLLECT_MS.
const SETTLE_MS = 1100;
const COLLECT_MS = 550;
// Sweep direction by the winner's seat offset from me: 0=me(bottom) 1=left 2=top 3=right.
const COLLECT_BY_OFFSET = ['collect-bottom', 'collect-left', 'collect-top', 'collect-right'];

export default function GameTable() {
  const navigate = useNavigate();
  const desktop = useIsDesktop();
  // Zooms the whole desktop board to fill the window (full width + height), so
  // cards, circles, text and the header all scale together. Up to 2.6×.
  const { containerRef, scale, contentWidth } = useFitScale([desktop], 860, 2.6);
  const myPlayer = useGameStore((s) => s.myPlayer);
  const gameStatus = useGameStore((s) => s.gameStatus);
  const hand = useGameStore((s) => s.hand);

  // Once a completed trick has been swept away, its key is remembered here so it
  // is not shown again while we wait for the winner to lead the next trick.
  const [dismissedKey, setDismissedKey] = useState<string | null>(null);
  // Turns on for the collect (fly-to-winner) phase, after the settle pause.
  const [collecting, setCollecting] = useState(false);

  const previousStash = gameStatus?.status.previous_stash ?? null;
  // Every game_status payload recreates the stash object, so identify the trick
  // by content — the timers must restart only when a *different* trick completes.
  const previousStashKey = previousStash
    ? `${previousStash.first_player}:${JSON.stringify(previousStash.cards)}`
    : null;

  useEffect(() => {
    if (!previousStashKey) return;
    setCollecting(false);
    const settle = setTimeout(() => setCollecting(true), SETTLE_MS);
    const done = setTimeout(() => {
      setCollecting(false);
      setDismissedKey(previousStashKey);
    }, SETTLE_MS + COLLECT_MS);
    return () => {
      clearTimeout(settle);
      clearTimeout(done);
    };
  }, [previousStashKey]);

  if (!gameStatus || !myPlayer) {
    return <p className="text-center text-green-dim pt-20 font-serif italic">Načítava sa…</p>;
  }

  const { completed, players, series_number, round_number, cards_in_round, status } = gameStatus;
  const {
    active_player,
    active_round_guesses,
    active_round_stashes,
    active_stash,
    standings = [],
    standings_guesses = [],
  } = status;

  if (completed) {
    return <GameOver players={players} standings={standings} />;
  }

  const myOrder = myPlayer.order;
  const isPlayPhase = active_stash !== undefined;
  const myTurnToPlay = isPlayPhase && active_player === myOrder;

  const activeCards = active_stash ? Object.keys(active_stash.cards).length : 0;
  // Once a player leads, that live trick always wins the centre. Otherwise, if a
  // just-completed trick hasn't been swept away yet, keep it face-up. Reading
  // `previousStash` synchronously (rather than a state set in an effect) means
  // the pile never blinks to empty on the frame the 4th card lands — the last
  // card simply joins the three already there, then the whole pile is collected.
  const finishing =
    previousStashKey !== null && previousStashKey !== dismissedKey && activeCards === 0;
  const displayedStash: StashData | null = finishing
    ? previousStash
    : activeCards > 0 && active_stash
      ? active_stash
      : null;

  // During the collect phase, sweep the pile towards whoever won it.
  const collectAnim =
    collecting && finishing && previousStash
      ? COLLECT_BY_OFFSET[(stashWinner(previousStash) - myOrder + 4) % 4]
      : null;

  const playableKeys = myTurnToPlay && active_stash
    ? computePlayable(hand, active_stash.cards[String(active_stash.first_player)]?.color ?? null)
    : undefined;

  const activePlayerName = players.find((p) => p.order === active_player)?.name ?? '';

  // Seat mapping relative to "Ty": left / across / right.
  const seat = (offset: number): PlayerInfo | undefined =>
    players.find((p) => p.order === (myOrder + offset) % 4);
  const leftP = seat(1);
  const topP = seat(2);
  const rightP = seat(3);

  // Live round state of one seat, shaped as PlayerCircle props.
  const seatProps = (o?: number) => ({
    won: o === undefined ? 0 : active_round_stashes?.[o] ?? 0,
    guess: (o === undefined ? null : active_round_guesses?.[String(o)] ?? null) as number | null,
    active: o !== undefined && active_player === o,
  });

  // Exact cards still in a player's hand: started with cards_in_round, lost one
  // per completed trick, minus one more if they've already played this trick.
  const completedTricks = (active_round_stashes ?? []).reduce((a, b) => a + b, 0);
  const cardsInHandOf = (o?: number) => {
    if (o === undefined) return 0;
    const playedCurrent = active_stash?.cards[String(o)] ? 1 : 0;
    return Math.max(0, cards_in_round - completedTricks - playedCurrent);
  };

  const handleLeave = () => leaveGame(navigate);
  const handleEnd = () => {
    if (window.confirm('Naozaj ukončiť celú hru pre všetkých?')) {
      emit.endGame(gameStatus.gid);
    }
  };
  // The host can always end the game; other players only when the host is
  // currently offline, so an abandoned game isn't stuck forever waiting for
  // a host who won't come back, but it isn't open to casual misuse otherwise.
  const hostConnected = players.find((p) => p.order === 0)?.connected ?? false;
  const canEnd = myOrder === 0 || !hostConnected;

  // ── shared pieces ────────────────────────────────────────────────
  const bannerText = active_player === myOrder
    ? isPlayPhase
      ? 'Zahraj kartu'
      : 'Zadaj tip'
    : `${activePlayerName} ${isPlayPhase ? 'hrá' : 'tipuje'}`;

  const banner = (
    <div className="flex items-center justify-center gap-2">
      <span className="inline-block w-[7px] h-[7px] rounded-full bg-gold animate-tp flex-shrink-0" />
      <span className="font-serif italic text-[13px] text-gold-dim tracking-[.03em]">{bannerText}</span>
    </div>
  );

  const opponents = players
    .filter((p) => p.order !== myOrder)
    .sort((a, b) => a.order - b.order);

  const totalsRow = (compact: boolean) => (
    <div className="flex items-center justify-between gap-2">
      {opponents.map((p) => (
        <div key={p.order} className="text-center">
          <div className="uppercase tracking-[.1em] text-green-dim mb-0.5" style={{ fontSize: 11 }}>
            {p.name}
          </div>
          <div className="font-serif text-green-score leading-none" style={{ fontSize: compact ? 16 : 20 }}>
            {computeTotal(standings, p.order)}
          </div>
        </div>
      ))}
      <div className="text-center rounded-lg px-3 py-1 bg-gold/[.06] border border-gold/[.15]">
        <div className="uppercase tracking-[.1em] text-gold mb-0.5" style={{ fontSize: 11 }}>
          {myPlayer.name}
        </div>
        <div className="font-serif font-semibold text-gold-dim leading-none" style={{ fontSize: compact ? 16 : 20 }}>
          {computeTotal(standings, myOrder)}
        </div>
      </div>
    </div>
  );

  // Center of the oval: trick during play, guess controls during bidding.
  const ovalContent = isPlayPhase ? (
    <div style={collectAnim ? { animation: `${collectAnim} ${COLLECT_MS}ms ease-in both` } : undefined}>
      <Trick stash={displayedStash} players={players} myOrder={myOrder} />
    </div>
  ) : (
    active_round_guesses !== undefined && active_player !== undefined ? (
      <GuessControls
        cardsInRound={cards_in_round}
        guesses={active_round_guesses}
        myOrder={myOrder}
        activePlayer={active_player}
        activePlayerName={activePlayerName}
      />
    ) : null
  );

  const topSeat = (
    <div className="flex flex-col items-center gap-1.5">
      <PlayerCircle name={topP?.name ?? '—'} {...seatProps(topP?.order)} size={desktop ? 64 : 52} />
      <FaceDownCards count={cardsInHandOf(topP?.order)} direction="row" desktop={desktop} />
    </div>
  );

  const sideSeat = (p?: PlayerInfo) => (
    <div className="flex flex-col items-center gap-1.5">
      <PlayerCircle name={p?.name ?? '—'} {...seatProps(p?.order)} size={desktop ? 60 : 48} />
      <FaceDownCards count={cardsInHandOf(p?.order)} direction="col" desktop={desktop} />
    </div>
  );

  const meSeat = (
    <div className="flex justify-center">
      <PlayerCircle name={myPlayer.name} {...seatProps(myOrder)} size={desktop ? 70 : 58} />
    </div>
  );

  const handArea = (
    <Hand hand={hand} myTurn={myTurnToPlay} isPlayPhase={isPlayPhase} playableKeys={playableKeys} desktop={desktop} />
  );

  // ── DESKTOP LAYOUT ───────────────────────────────────────────────
  if (desktop) {
    return (
      <div ref={containerRef} className="h-[100dvh] w-full overflow-hidden bg-table">
        {/* Design canvas — fixed height, width spans the viewport; scaled as one
            unit so the whole board (and header) zooms with the window. */}
        <div
          className="flex"
          style={{ width: contentWidth, height: 860, transform: `scale(${scale})`, transformOrigin: 'top left' }}
        >
          {/* main */}
          <div className="flex-1 min-w-0 flex flex-col">
            {/* header */}
            <div className="shrink-0 h-[58px] bg-header flex items-center gap-4 px-6 border-b border-[#14221a]">
              <span className="font-serif uppercase tracking-[.14em] text-[15px] text-gold whitespace-nowrap">
                Bridžik
              </span>
              <div className="w-px h-[22px] bg-[#1a3a22]" />
              <span className="font-serif text-[12px] text-green-dim tracking-[.06em] whitespace-nowrap">
                Séria {series_number + 1} · Kolo {round_number + 1}
              </span>
              <div className="flex-1 flex items-center justify-center">{banner}</div>
              {totalsRow(true)}
              <div className="w-px h-[22px] bg-[#1a3a22]" />
              {canEnd && (
                <button onClick={handleEnd} className="text-[11px] text-[#8a8064] hover:text-gold whitespace-nowrap">
                  Ukončiť
                </button>
              )}
              <button onClick={handleLeave} className="text-[11px] text-[#7a7058] hover:text-gold whitespace-nowrap">
                Odísť
              </button>
            </div>

            {/* game content — players hug the edges so the felt uses full width */}
            <div className="flex-1 min-h-0 flex flex-col justify-center gap-3 px-16 py-4">
              {topSeat}

              <div className="flex items-center justify-center gap-16">
                {sideSeat(leftP)}
                <div
                  className="flex items-center justify-center rounded-full"
                  style={{
                    width: 620,
                    height: 372,
                    background:
                      'radial-gradient(ellipse at 42% 38%,#306845 0%,#1e5030 38%,#122e1c 72%,#091e12 100%)',
                    boxShadow:
                      'inset 0 10px 48px rgba(0,0,0,.72),0 0 0 3px rgba(0,0,0,.55),0 0 0 6px rgba(201,168,76,.1)',
                  }}
                >
                  {ovalContent}
                </div>
                {sideSeat(rightP)}
              </div>

              {meSeat}
            </div>

            {handArea}
          </div>

          {/* sidebar */}
          <Standings standings={standings} guesses={standings_guesses} players={players} myOrder={myOrder} desktop />
        </div>
      </div>
    );
  }

  // ── MOBILE LAYOUT ────────────────────────────────────────────────
  return (
    <div className="max-w-lg mx-auto min-h-screen flex flex-col">
      {/* header */}
      <div className="bg-header px-[18px] pt-[14px] pb-3 border-b border-[#14221a]">
        <div className="flex items-center justify-between mb-2.5">
          <span className="font-serif uppercase tracking-[.1em] text-[11px] text-gold">
            Séria {series_number + 1} · Kolo {round_number + 1}
          </span>
          <div className="flex items-center gap-3">
            {canEnd && (
              <button onClick={handleEnd} className="text-[11px] text-[#6a3030] hover:text-red-400">
                Ukončiť
              </button>
            )}
            <button onClick={handleLeave} className="text-[11px] text-[#7a7058] hover:text-gold">
              Odísť
            </button>
          </div>
        </div>
        {totalsRow(false)}
      </div>

      {/* turn banner */}
      <div
        className="py-[9px] px-4 border-b border-[#152a1a]"
        style={{ background: 'linear-gradient(90deg,#09190d,#14301e,#09190d)' }}
      >
        {banner}
      </div>

      {/* game area */}
      <div className="flex-1 bg-table px-2.5 pt-2.5 pb-1.5 flex flex-col">
        <div className="flex flex-col items-center mb-1.5">{topSeat}</div>

        <div className="flex items-center gap-1.5 mb-2">
          <div className="w-[54px] flex-shrink-0 flex justify-center">{sideSeat(leftP)}</div>
          <div
            className="flex-1 flex items-center justify-center rounded-full"
            style={{
              minHeight: 192,
              background:
                'radial-gradient(ellipse at 42% 38%,#306845 0%,#1e5030 38%,#122e1c 72%,#091e12 100%)',
              boxShadow:
                'inset 0 6px 32px rgba(0,0,0,.7),0 0 0 2px rgba(0,0,0,.5),0 0 0 4px rgba(201,168,76,.1)',
            }}
          >
            {ovalContent}
          </div>
          <div className="w-[54px] flex-shrink-0 flex justify-center">{sideSeat(rightP)}</div>
        </div>

        <div className="mb-1.5">{meSeat}</div>
      </div>

      {handArea}

      {/* score */}
      <div className="bg-table px-3 pb-4 pt-1">
        <Standings standings={standings} guesses={standings_guesses} players={players} myOrder={myOrder} />
      </div>
    </div>
  );
}
