import { useState, useEffect, useCallback, useRef } from 'react';
import { usePersistence } from './hooks/usePersistence.js';
import { useGame } from './hooks/useGame.js';
import { getDaily, postPlayAgain } from './api.js';
import { Screen1Rules } from './screens/Screen1Rules.js';
import { Screen2Game } from './screens/Screen2Game.js';
import { Screen3Results } from './screens/Screen3Results.js';

type Screen = 'rules' | 'game' | 'results';

export default function App() {
  const { state, updateState } = usePersistence();
  const [screen, setScreen] = useState<Screen>('game');
  const [wordId, setWordId] = useState<number | null>(null);
  const {
    guesses, gameStatus, message, lastDifficulty, revealedWord, replays,
    submitGuess, dismissMessage, resetForNewGame,
  } = useGame(state.currentGame?.guesses ?? []);
  const initialised = useRef(false);

  // Initialize from persisted state
  useEffect(() => {
    if (initialised.current) return;
    initialised.current = true;

    if (state.currentGame) {
      setWordId(state.currentGame.wordId);
      setScreen('game');
      return;
    }

    if (!state.rulesSeen) {
      setScreen('rules');
      return;
    }

    setScreen('game');
    getDaily()
      .then((res) => setWordId(res.wordId))
      .catch(() => {});
  }, [state]);

  // Compute letter colors for keyboard
  const letterColors: Record<string, string | undefined> = {};
  for (const entry of guesses) {
    for (let i = 0; i < entry.guess.length; i++) {
      const letter = entry.guess[i];
      const color = entry.colors[i];
      if (color === 'g' || (color === 'y' && letterColors[letter] !== 'g') || (color === 'x' && !letterColors[letter])) {
        letterColors[letter] = color;
      }
    }
  }

  const handleGuess = useCallback(
    async (guess: string) => {
      if (wordId === null) return false;
      return submitGuess(wordId, guess);
    },
    [wordId, submitGuess]
  );

  // Persist game state on changes
  useEffect(() => {
    if (wordId !== null && guesses.length > 0 && gameStatus === 'playing') {
      updateState({ currentGame: { wordId, guesses } });
    }
  }, [guesses, wordId, gameStatus, updateState]);

  // Handle game end — compute stats and running-average skill metric
  useEffect(() => {
    if (gameStatus !== 'won' && gameStatus !== 'lost') return;

    const stats = { ...state.stats };
    stats.gamesPlayed++;

    if (gameStatus === 'won') {
      stats.wins++;
      stats.currentStreak++;
      if (stats.currentStreak > stats.maxStreak) stats.maxStreak = stats.currentStreak;
      const attemptIdx = guesses.length - 1;
      if (attemptIdx >= 0 && attemptIdx < 7) {
        stats.histogram = [...stats.histogram];
        stats.histogram[attemptIdx]++;
      }
    } else {
      stats.currentStreak = 0;
      stats.histogram = [...stats.histogram];
      stats.histogram[6]++;
    }

    // Running average skill metric
    const diff = lastDifficulty ?? 3.0;
    const newSkill = state.stats.gamesPlayed > 0
      ? (state.skillMetric * state.stats.gamesPlayed + diff) / (state.stats.gamesPlayed + 1)
      : diff;

    updateState({
      stats,
      currentGame: undefined,
      skillMetric: newSkill,
    });
    setScreen('results');
  }, [gameStatus]); // Only on status change

  const handlePlay = useCallback(() => {
    updateState({ rulesSeen: true });
    setScreen('game');
    getDaily()
      .then((res) => setWordId(res.wordId))
      .catch(() => {});
  }, [updateState]);

  const handlePlayAgain = useCallback(async () => {
    const skillMetric = state.skillMetric;
    try {
      const res = await postPlayAgain({ skillMetric });
      setWordId(res.wordId);
      resetForNewGame();
      setScreen('game');
    } catch {
      // If server unreachable, stay on results
    }
  }, [state.skillMetric, resetForNewGame]);

  if (screen === 'rules') {
    return <Screen1Rules onPlay={handlePlay} />;
  }

  if (screen === 'results') {
    // On win, the last guess IS the target word. On loss, the server reveals it.
    const targetWord =
      revealedWord ??
      (gameStatus === 'won' ? guesses[guesses.length - 1]?.guess ?? null : null);

    return (
      <Screen3Results
        won={gameStatus === 'won'}
        attemptCount={guesses.length}
        revealedWord={targetWord}
        stats={state.stats}
        replays={replays ?? undefined}
        onPlayAgain={handlePlayAgain}
      />
    );
  }

  return (
    <Screen2Game
      guesses={guesses}
      letterColors={letterColors}
      message={message}
      onGuess={handleGuess}
      onDismissMessage={dismissMessage}
      gameOver={gameStatus !== 'playing'}
    />
  );
}
