import { createFileRoute } from "@tanstack/react-router";
import { useEffect, useState, useCallback } from "react";
import { useWsClient, useWsConnected } from "../../lib/ws-hooks.js";
import { QuestionCard } from "../../components/game/QuestionCard.js";
import { MultiplayerScoreScreen } from "../../components/multiplayer/MultiplayerScoreScreen.js";
import { GameRouteSearchSchema } from "@lila/shared";
import type {
  WsGameQuestion,
  WsGameAnswerResult,
  WsGameFinished,
  WsError,
} from "@lila/shared";

export const Route = createFileRoute("/multiplayer/game/$code")({
  component: GamePage,
  validateSearch: GameRouteSearchSchema,
});

function GamePage() {
  const { code } = Route.useParams();
  const { lobbyId } = Route.useSearch();
  const { session } = Route.useRouteContext();
  const currentUserId = session.user.id;
  const client = useWsClient();
  const isConnected = useWsConnected();

  const [currentQuestion, setCurrentQuestion] = useState<WsGameQuestion | null>(
    null,
  );
  const [answerResult, setAnswerResult] = useState<WsGameAnswerResult | null>(
    null,
  );
  const [gameFinished, setGameFinished] = useState<WsGameFinished | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [hasAnswered, setHasAnswered] = useState(false);

  const handleGameQuestion = useCallback((msg: WsGameQuestion) => {
    setCurrentQuestion(msg);
    setAnswerResult(null);
    setHasAnswered(false);
    setError(null);
  }, []);

  const handleAnswerResult = useCallback((msg: WsGameAnswerResult) => {
    setAnswerResult(msg);
  }, []);

  const handleGameFinished = useCallback((msg: WsGameFinished) => {
    setGameFinished(msg);
  }, []);

  const handleWsError = useCallback((msg: WsError) => {
    setError(msg.message);
  }, []);

  useEffect(() => {
    if (!isConnected) return;

    client.on("game:question", handleGameQuestion);
    client.on("game:answer_result", handleAnswerResult);
    client.on("game:finished", handleGameFinished);
    client.on("error", handleWsError);

    client.send({ type: "game:ready", lobbyId });

    return () => {
      client.off("game:question", handleGameQuestion);
      client.off("game:answer_result", handleAnswerResult);
      client.off("game:finished", handleGameFinished);
      client.off("error", handleWsError);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isConnected]);

  const handleAnswer = useCallback(
    (optionId: number) => {
      if (hasAnswered || !currentQuestion) return;
      setHasAnswered(true);
      client.send({
        type: "game:answer",
        lobbyId,
        questionId: currentQuestion.question.questionId,
        selectedOptionId: optionId,
      });
    },
    [hasAnswered, currentQuestion, client, lobbyId],
  );

  // Phase: finished
  if (gameFinished) {
    return (
      <MultiplayerScoreScreen
        players={gameFinished.players}
        winnerIds={gameFinished.winnerIds}
        currentUserId={currentUserId}
        lobbyCode={code}
      />
    );
  }

  // Phase: loading
  if (!isConnected || !currentQuestion) {
    return (
      <div className="min-h-screen bg-linear-to-b from-purple-100 to-pink-50 flex items-center justify-center">
        <p className="text-purple-400 text-lg font-medium">
          {error ?? (isConnected ? "Loading game..." : "Connecting...")}
        </p>
      </div>
    );
  }

  // Phase: playing
  return (
    <div className="min-h-screen bg-linear-to-b from-purple-100 to-pink-50 flex items-center justify-center p-6">
      <div className="w-full max-w-md rounded-3xl border border-(--color-primary-light) bg-white/50 dark:bg-black/10 backdrop-blur shadow-sm p-8 flex flex-col gap-6">
        {/* Progress */}
        <p className="text-xs font-bold tracking-widest uppercase text-(--color-text-muted) text-center">
          Question {currentQuestion.questionNumber} of{" "}
          {currentQuestion.totalQuestions}
        </p>

        {/* Question */}
        <QuestionCard
          question={currentQuestion.question}
          questionNumber={currentQuestion.questionNumber}
          totalQuestions={currentQuestion.totalQuestions}
          currentResult={
            answerResult
              ? {
                  questionId: currentQuestion.question.questionId,
                  isCorrect:
                    answerResult.results.find((r) => r.userId === currentUserId)
                      ?.isCorrect ?? false,
                  correctOptionId: answerResult.correctOptionId,
                  selectedOptionId:
                    answerResult.results.find((r) => r.userId === currentUserId)
                      ?.selectedOptionId ?? 0,
                }
              : null
          }
          onAnswer={handleAnswer}
          onNext={() => {
            setAnswerResult(null);
          }}
        />

        {/* Error */}
        {error && <p className="text-red-500 text-sm text-center">{error}</p>}

        {/* Round results */}
        {answerResult && (
          <div className="flex flex-col gap-2">
            <h3 className="text-sm font-black text-(--color-text)">
              Round results
            </h3>
            {answerResult.players.map((player) => {
              const result = answerResult.results.find(
                (r) => r.userId === player.userId,
              );
              return (
                <div
                  key={player.userId}
                  className="flex items-center justify-between text-sm text-(--color-text)"
                >
                  <span className="font-semibold">{player.user.name}</span>
                  <span
                    className={
                      result?.isCorrect
                        ? "text-green-600 font-medium"
                        : "text-red-500"
                    }
                  >
                    {result?.selectedOptionId === null
                      ? "Timed out"
                      : result?.isCorrect
                        ? "✓ Correct"
                        : "✗ Wrong"}
                  </span>
                  <span className="text-(--color-text-muted)">
                    {player.score} pts
                  </span>
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}
