import { useEffect, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useSearchParams } from "react-router-dom";

import { api } from "../api/client";
import { useWalkupContext } from "../hooks/useWalkupContext";
import { loadPreparedGame, savePreparedGame } from "../lib/offlinePrep";
import { queryClient } from "../lib/queryClient";
import { formatGameDate, formatGameTitle, formatMemberName, formatTeamLabel } from "../lib/teamsnapHelpers";

export function GamePage() {
  const walkup = useWalkupContext();
  const [searchParams, setSearchParams] = useSearchParams();
  const [selectedGameId, setSelectedGameId] = useState(searchParams.get("gameId") ?? "");
  const [clipId, setClipId] = useState<number>(0);
  const [slot, setSlot] = useState<number>(1);
  const [offlineMessage, setOfflineMessage] = useState<string | null>(null);
  const teamId = walkup.selectedTeamId;
  const playerId = walkup.currentPlayerId;

  useEffect(() => {
    const requestedGameId = searchParams.get("gameId");
    if (requestedGameId) {
      setSelectedGameId(requestedGameId);
      return;
    }
    if (!selectedGameId && walkup.nextGame) {
      setSelectedGameId(String(walkup.nextGame.id));
    }
  }, [searchParams, selectedGameId, walkup.nextGame]);

  const clipsQuery = useQuery({
    queryKey: ["clips", teamId, playerId, "visible"],
    queryFn: () => api.listClips(teamId, playerId),
    enabled: Boolean(teamId && playerId),
    networkMode: "always",
    retry: 0,
  });
  const assignmentsQuery = useQuery({
    queryKey: ["assignments", selectedGameId, playerId],
    queryFn: () => api.listAssignments(selectedGameId, playerId),
    enabled: Boolean(selectedGameId && playerId),
    networkMode: "always",
    retry: 0,
  });
  const prepQuery = useQuery({
    queryKey: ["prep", selectedGameId],
    queryFn: () => api.prepareGame(selectedGameId),
    enabled: Boolean(selectedGameId),
    networkMode: "always",
    retry: 0,
  });

  const saveMutation = useMutation({
    mutationFn: () =>
      api.createAssignment(selectedGameId, {
        external_team_id: teamId,
        external_player_id: playerId,
        clip_id: clipId,
        batting_slot: slot,
        status: "ready",
      }),
    onSuccess: async () => {
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ["assignments", selectedGameId, playerId] }),
        queryClient.invalidateQueries({ queryKey: ["prep", selectedGameId] }),
      ]);
    },
  });

  const unpinMutation = useMutation({
    mutationFn: (assignmentId: number) => api.deleteAssignment(selectedGameId, assignmentId, playerId),
    onSuccess: async () => {
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ["assignments", selectedGameId, playerId] }),
        queryClient.invalidateQueries({ queryKey: ["prep", selectedGameId] }),
      ]);
    },
  });

  function selectGame(gameId: string) {
    setSelectedGameId(gameId);
    setSearchParams({ gameId });
    setOfflineMessage(null);
  }

  function cachePreparedGame() {
    if (!prepQuery.data) {
      setOfflineMessage("Prepare the game first so there is something to cache locally.");
      return;
    }
    savePreparedGame(selectedGameId, prepQuery.data);
    setOfflineMessage(`Cached ${prepQuery.data.assignments.length} pinned clips for offline gameday use.`);
  }

  const selectedGame = walkup.games.find((game) => String(game.id) === selectedGameId) ?? null;
  const cachedPrep = selectedGameId ? loadPreparedGame(selectedGameId) : null;

  if (!walkup.isTeamSnap) {
    return (
      <section className="container-fluid py-4">
        <div className="card shadow-sm">
          <div className="card-body">Reconnect with TeamSnap to pin clips to games.</div>
        </div>
      </section>
    );
  }

  if (!teamId || !playerId) {
    return (
      <section className="container-fluid py-4">
        <div className="card shadow-sm">
          <div className="card-body">
            No player record was found on the selected team, so game-specific clip selection is unavailable.
          </div>
        </div>
      </section>
    );
  }

  return (
    <section className="container-fluid py-4 d-grid gap-4">
      <div className="card bg-dark text-white border-0 shadow-sm">
        <div className="card-body p-4 p-lg-5">
          <p className="text-uppercase small text-info-emphasis mb-2">Pinned clips</p>
          <h1 className="h2">{selectedGame ? formatGameTitle(selectedGame) : "Select a game"}</h1>
          <p className="mb-0 text-white-50">
            {formatMemberName(walkup.currentPlayer)} can pin clips from song files in their own library to any game on{" "}
            {formatTeamLabel(walkup.selectedTeam)}.
          </p>
        </div>
      </div>
      <div className="row g-4">
        <div className="col-12 col-xl-6">
          <div className="card shadow-sm h-100">
            <div className="card-body d-grid gap-3">
              <div className="d-grid gap-2">
                <label className="form-label d-grid gap-2">
                  <span>Selected game</span>
                  <select className="form-select" value={selectedGameId} onChange={(event) => selectGame(event.target.value)}>
                    <option value="">Select a game</option>
                    {walkup.games.map((game) => (
                      <option key={String(game.id)} value={String(game.id)}>
                        {formatGameTitle(game)}
                      </option>
                    ))}
                  </select>
                </label>
                <div className="text-body-secondary">
                  {selectedGame ? formatGameDate(selectedGame) : "Choose a game to pin clips."}
                </div>
                {walkup.nextGame ? <div className="text-body-secondary">Next game: {formatGameTitle(walkup.nextGame)}</div> : null}
              </div>
            </div>
          </div>
        </div>
        <div className="col-12 col-xl-6">
          <div className="card shadow-sm h-100">
            <div className="card-body d-grid gap-3">
          <h2 className="h4 mb-0">Pin a clip</h2>
          {selectedGame ? (
            <>
              <div className="text-body-secondary">{formatGameDate(selectedGame)}</div>
              <label className="form-label d-grid gap-2">
                <span>Clip</span>
                <select className="form-select" value={clipId} onChange={(event) => setClipId(Number(event.target.value))}>
                  <option value={0}>Select clip</option>
                  {clipsQuery.data?.map((clip) => (
                    <option key={clip.id} value={clip.id}>
                      {clip.label} from song {clip.asset_title}
                    </option>
                  ))}
                </select>
              </label>
              <label className="form-label d-grid gap-2">
                <span>Suggested batting slot</span>
                <input className="form-control" type="number" value={slot} onChange={(event) => setSlot(Number(event.target.value))} />
              </label>
              <button type="button" className="btn btn-primary" disabled={!clipId} onClick={() => void saveMutation.mutateAsync()}>
                {saveMutation.isPending ? "Saving..." : "Pin clip to this game"}
              </button>
              {saveMutation.error instanceof Error ? <div className="text-body-secondary">{saveMutation.error.message}</div> : null}
            </>
          ) : (
            <div className="text-body-secondary">Pick a game to pin clips.</div>
          )}
            </div>
          </div>
        </div>
      </div>
      <div className="row g-4">
        <div className="col-12 col-xl-6">
          <div className="card shadow-sm h-100">
            <div className="card-body d-grid gap-3">
              <h2 className="h4 mb-0">Pinned clips</h2>
              <div className="list-group">
            {assignmentsQuery.data?.map((assignment) => (
              <div className="list-group-item d-flex justify-content-between align-items-center gap-3" key={assignment.id}>
                <div className="d-grid gap-1">
                  <strong>{assignment.clip_label}</strong>
                  <div className="text-body-secondary">
                    {assignment.asset_title} {assignment.batting_slot ? `| slot ${assignment.batting_slot}` : ""}
                  </div>
                </div>
                <button
                  type="button"
                  className="btn btn-sm icon-button icon-button-circle btn-outline-secondary"
                  onClick={() => void unpinMutation.mutateAsync(assignment.id)}
                  aria-label="Unpin clip"
                  title="Unpin clip"
                >
                  <i className="bi bi-pin-angle" aria-hidden="true" />
                </button>
              </div>
            ))}
            {!assignmentsQuery.isLoading && !assignmentsQuery.data?.length ? (
              <div className="text-body-secondary">No clips pinned to this game yet.</div>
            ) : null}
              </div>
            </div>
          </div>
        </div>
        <div className="col-12 col-xl-6">
          <div className="card shadow-sm h-100">
            <div className="card-body d-grid gap-3">
              <h2 className="h4 mb-0">Prepared payload</h2>
              <div className="d-grid gap-2">
                <div className="text-body-secondary">Prepared at: {prepQuery.data?.prepared_at ?? "Not prepared yet"}</div>
                <div className="text-body-secondary">Pinned clips in package: {prepQuery.data?.assignments.length ?? 0}</div>
                <div className="text-body-secondary">Cached locally: {cachedPrep ? `${cachedPrep.assignments.length} pinned clips` : "No"}</div>
              </div>
            <button type="button" className="btn btn-outline-secondary" onClick={cachePreparedGame} disabled={!selectedGameId}>
              Cache on this device
            </button>
              {offlineMessage ? <div className="text-body-secondary">{offlineMessage}</div> : null}
            </div>
          </div>
        </div>
      </div>
    </section>
  );
}
