import { Link, useFetcher } from "react-router";
import { auth } from "~/lib/auth.server";
import type { Route } from "./+types/admin.tournaments.$id";

import { logger } from "~/lib/logger";
import {
  getTournamentById,
  updateTournamentStatus,
} from "~/models/tournament";
import {
  getTournamentResults,
  upsertTournamentResult,
} from "~/models/tournament-result";
import { findCanonicalParticipantsBySport } from "~/models/participant";
import { isUserAdmin } from "~/models/user";
import {
  syncTournamentResults,
  type SyncReport,
} from "~/services/sync-tournament-results";
import { getSportsSeasonsByTournament } from "~/models/scoring-event";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "~/components/ui/card";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "~/components/ui/table";
import { ArrowLeft, CheckCircle2, AlertTriangle } from "lucide-react";
import { BatchResultEntry } from "~/components/BatchResultEntry";

export function meta({ data }: Route.MetaArgs): Route.MetaDescriptors {
  return [
    {
      title: `${data?.tournament?.name ?? "Tournament"} - Brackt Admin`,
    },
  ];
}

export async function loader({ params }: Route.LoaderArgs) {
  const tournament = await getTournamentById(params.id);
  if (!tournament) {
    throw new Response("Not Found", { status: 404 });
  }

  const [results, canonicalParticipants, linkedSportsSeasons] = await Promise.all([
    getTournamentResults(tournament.id),
    findCanonicalParticipantsBySport(tournament.sportId),
    getSportsSeasonsByTournament(tournament.id),
  ]);

  return { tournament, results, canonicalParticipants, linkedSportsSeasons };
}

export async function action(args: Route.ActionArgs) {
  const { request, params } = args;
  const session = await auth.api.getSession({ headers: request.headers });
  const userId = session?.user.id ?? null;
  const isAdmin = userId ? await isUserAdmin(userId) : false;
  if (!isAdmin) {
    throw new Response("Forbidden", { status: 403 });
  }

  const tournament = await getTournamentById(params.id);
  if (!tournament) {
    throw new Response("Not Found", { status: 404 });
  }

  const formData = await request.formData();
  const intent = formData.get("intent");

  if (intent === "batch-upsert-results") {
    const resultsRaw = formData.get("results");
    if (typeof resultsRaw !== "string" || !resultsRaw) {
      return {
        success: false as const,
        error: "Missing results payload",
        syncReport: null,
      };
    }

    let parsed: Array<{ participantId: string; placement: number }>;
    try {
      parsed = JSON.parse(resultsRaw);
    } catch {
      return {
        success: false as const,
        error: "Invalid JSON in results payload",
        syncReport: null,
      };
    }

    if (!Array.isArray(parsed)) {
      return {
        success: false as const,
        error: "Results payload must be an array",
        syncReport: null,
      };
    }

    try {
      for (const row of parsed) {
        if (
          !row ||
          typeof row.participantId !== "string" ||
          typeof row.placement !== "number"
        ) {
          return {
            success: false as const,
            error: "Each result must have participantId and placement",
            syncReport: null,
          };
        }
        await upsertTournamentResult({
          tournamentId: tournament.id,
          participantId: row.participantId,
          placement: row.placement,
        });
      }

      if (tournament.status !== "completed") {
        await updateTournamentStatus(tournament.id, "completed");
      }

      const syncReport = await syncTournamentResults(tournament.id);
      return {
        success: true as const,
        error: null,
        syncReport,
      };
    } catch (error) {
      logger.error("batch-upsert-results failed:", error);
      return {
        success: false as const,
        error:
          error instanceof Error ? error.message : "Failed to save results",
        syncReport: null,
      };
    }
  }

  if (intent === "retry-window-sync") {
    try {
      const syncReport = await syncTournamentResults(tournament.id);
      return { success: true as const, error: null, syncReport };
    } catch (error) {
      logger.error("retry-window-sync failed:", error);
      return {
        success: false as const,
        error:
          error instanceof Error ? error.message : "Failed to retry sync",
        syncReport: null,
      };
    }
  }

  return {
    success: false as const,
    error: "Invalid intent",
    syncReport: null,
  };
}

export default function AdminTournamentDetail({
  loaderData,
  actionData,
}: Route.ComponentProps) {
  const { tournament, results, canonicalParticipants, linkedSportsSeasons } = loaderData;
  const retryFetcher = useFetcher<typeof action>();

  // Prefer the latest action/retry response for the sync report
  const liveReport: SyncReport | null =
    (retryFetcher.data?.syncReport ?? actionData?.syncReport) ?? null;

  const participantById = new Map(
    canonicalParticipants.map((p) => [p.id, p])
  );

  return (
    <div className="p-8">
      <div className="max-w-5xl">
        <div className="mb-6">
          <Button variant="ghost" size="sm" asChild className="mb-2">
            <Link to="/admin/tournaments">
              <ArrowLeft className="mr-2 h-4 w-4" />
              Back to tournaments
            </Link>
          </Button>
          <div className="flex items-center gap-3">
            <h1 className="text-3xl font-bold">{tournament.name}</h1>
            <Badge
              variant={
                tournament.status === "completed"
                  ? "default"
                  : tournament.status === "in_progress"
                  ? "secondary"
                  : "outline"
              }
            >
              {tournament.status}
            </Badge>
          </div>
          <p className="text-muted-foreground mt-1">
            {tournament.year}
            {tournament.location ? ` — ${tournament.location}` : ""}
            {tournament.surface ? ` — ${tournament.surface}` : ""}
          </p>
        </div>

        {liveReport && (
          <Card className="mb-6 border-emerald-500/30">
            <CardHeader>
              <CardTitle className="flex items-center gap-2 text-emerald-500">
                <CheckCircle2 className="h-5 w-5" />
                Synced to {liveReport.windowsSynced}{" "}
                {liveReport.windowsSynced === 1 ? "window" : "windows"}
              </CardTitle>
              <CardDescription>
                Canonical results were fanned out to every linked scoring
                window.
              </CardDescription>
            </CardHeader>
            {liveReport.failures.length > 0 && (
              <CardContent>
                <div className="rounded-md border border-destructive/50 bg-destructive/10 p-4 space-y-3">
                  <div className="flex items-center gap-2 text-destructive font-medium">
                    <AlertTriangle className="h-4 w-4" />
                    {liveReport.failures.length}{" "}
                    {liveReport.failures.length === 1 ? "window" : "windows"}{" "}
                    failed to sync
                  </div>
                  <div className="space-y-2">
                    {liveReport.failures.map((f) => (
                      <div
                        key={f.scoringEventId}
                        className="flex items-start justify-between gap-4 text-sm"
                      >
                        <div className="space-y-1">
                          <div className="font-mono text-xs text-muted-foreground">
                            event: {f.scoringEventId}
                          </div>
                          <div className="font-mono text-xs text-muted-foreground">
                            season: {f.sportsSeasonId}
                          </div>
                          <div className="text-destructive">{f.error}</div>
                        </div>
                        <retryFetcher.Form method="post">
                          <input
                            type="hidden"
                            name="intent"
                            value="retry-window-sync"
                          />
                          <input
                            type="hidden"
                            name="scoringEventId"
                            value={f.scoringEventId}
                          />
                          <Button
                            type="submit"
                            size="sm"
                            variant="outline"
                            disabled={retryFetcher.state !== "idle"}
                          >
                            {retryFetcher.state !== "idle"
                              ? "Retrying…"
                              : "Retry"}
                          </Button>
                        </retryFetcher.Form>
                      </div>
                    ))}
                  </div>
                </div>
              </CardContent>
            )}
          </Card>
        )}

        <Card className="mb-6">
          <CardHeader>
            <CardTitle>Linked Sports Seasons</CardTitle>
            <CardDescription>
              {linkedSportsSeasons.length}{" "}
              {linkedSportsSeasons.length === 1
                ? "sports season"
                : "sports seasons"}{" "}
              use this tournament as a scoring event
            </CardDescription>
          </CardHeader>
          <CardContent>
            {linkedSportsSeasons.length > 0 ? (
              <div className="space-y-2">
                {linkedSportsSeasons.map((link) => (
                  <div
                    key={link.id}
                    className="flex items-center justify-between p-3 border rounded-lg"
                  >
                    <div>
                      <p className="font-medium">
                        {link.sportsSeason.sport.name} -{" "}
                        {link.sportsSeason.name}
                      </p>
                      <p className="text-sm text-muted-foreground">
                        {link.sportsSeason.year} &bull;{" "}
                        {link.sportsSeason.scoringType.replace("_", " ")}
                      </p>
                    </div>
                    <Badge
                      variant={
                        link.sportsSeason.status === "completed"
                          ? "default"
                          : link.sportsSeason.status === "active"
                          ? "secondary"
                          : "outline"
                      }
                    >
                      {link.sportsSeason.status}
                    </Badge>
                  </div>
                ))}
              </div>
            ) : (
              <p className="text-sm text-muted-foreground text-center py-4">
                No sports seasons are using this tournament yet.
              </p>
            )}
          </CardContent>
        </Card>

        <div className="grid gap-6 md:grid-cols-2">
          <Card>
            <CardHeader>
              <CardTitle>Current Results</CardTitle>
              <CardDescription>
                {results.length}{" "}
                {results.length === 1 ? "result" : "results"} recorded
              </CardDescription>
            </CardHeader>
            <CardContent>
              {results.length === 0 ? (
                <p className="text-sm text-muted-foreground py-6 text-center">
                  No results recorded yet. Paste a ranked list to the right to
                  import.
                </p>
              ) : (
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead className="w-24">Placement</TableHead>
                      <TableHead>Participant</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {results.map((r) => {
                      const p = participantById.get(r.participantId);
                      return (
                        <TableRow key={r.id}>
                          <TableCell className="font-semibold">
                            {r.placement ?? "—"}
                          </TableCell>
                          <TableCell>
                            {p?.name ?? (
                              <span className="text-muted-foreground font-mono text-xs">
                                {r.participantId}
                              </span>
                            )}
                          </TableCell>
                        </TableRow>
                      );
                    })}
                  </TableBody>
                </Table>
              )}
            </CardContent>
          </Card>

          <BatchResultEntry
            participants={canonicalParticipants.map((p) => ({
              id: p.id,
              name: p.name,
            }))}
            sportsSeasonId=""
            existingResultParticipantIds={
              new Set(results.map((r) => r.participantId))
            }
            intent="batch-upsert-results"
          />
        </div>
      </div>
    </div>
  );
}
