import { useState, useRef, useEffect } from "react";
import { useFetcher, useRevalidator } from "react-router";
import { Button } from "~/components/ui/button";
import { Textarea } from "~/components/ui/textarea";
import { Input } from "~/components/ui/input";
import { Badge } from "~/components/ui/badge";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "~/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "~/components/ui/table";
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from "~/components/ui/card";
import { CheckCircle2, Trophy } from "lucide-react";
import { parseResultsText } from "~/lib/parse-results-text";

interface Participant {
  id: string;
  name: string;
}

interface ResolvedRow {
  placement: number;
  rawName: string;
  participantId: string | null; // null = unresolved
}

type Stage = "idle" | "preview" | "saving";

interface BatchResultEntryProps {
  participants: Participant[];
  sportsSeasonId: string;
  existingResultParticipantIds: Set<string>;
  /**
   * Form intent name posted on "Save All". Defaults to "batch-add-results" for
   * the existing per-window flow. Canonical tournament pages override this.
   */
  intent?: string;
}

export function BatchResultEntry({
  participants,
  sportsSeasonId,
  existingResultParticipantIds,
  intent = "batch-add-results",
}: BatchResultEntryProps) {
  const [stage, setStage] = useState<Stage>("idle");
  const [pasteText, setPasteText] = useState("");
  const [rows, setRows] = useState<ResolvedRow[]>([]);
  const [parseError, setParseError] = useState<string | null>(null);
  const [successMessage, setSuccessMessage] = useState<string | null>(null);
  const [addingNewFor, setAddingNewFor] = useState<number | null>(null);
  const [newParticipantName, setNewParticipantName] = useState("");
  const { revalidate } = useRevalidator();

  const saveFetcher = useFetcher();
  const createParticipantFetcher = useFetcher();

  // Mutable lookup built from the prop — updated when new participants are created
  const participantByNameRef = useRef(
    new Map(participants.map((p) => [p.name.toLowerCase(), p]))
  );
  // Mutable list — grows when new participants are created inline
  const participantsRef = useRef([...participants]);

  const pendingNewParticipantRowRef = useRef<number | null>(null);

  const createData = createParticipantFetcher.data as
    | { newParticipant?: { id: string; name: string }; error?: string }
    | undefined;

  const saveData = saveFetcher.data as
    | { success?: string; error?: string }
    | undefined;

  // When createParticipantFetcher returns a new participant, auto-select it
  useEffect(() => {
    if (
      createData?.newParticipant &&
      pendingNewParticipantRowRef.current !== null
    ) {
      const newP = createData.newParticipant;
      const rowIndex = pendingNewParticipantRowRef.current;
      pendingNewParticipantRowRef.current = null;
      // Update lookup and list
      participantByNameRef.current.set(newP.name.toLowerCase(), newP);
      participantsRef.current.push(newP);
      // Auto-select for the row
      setRows((prev) =>
        prev.map((row, i) =>
          i === rowIndex ? { ...row, participantId: newP.id } : row
        )
      );
    }
  }, [createData]);

  // Watch save fetcher for completion
  useEffect(() => {
    if (stage === "saving" && saveFetcher.state === "idle" && saveData) {
      if (saveData.success) {
        setSuccessMessage(saveData.success);
        setStage("idle");
        setPasteText("");
        setRows([]);
        revalidate();
      } else if (saveData.error) {
        setStage("preview");
      }
    }
  }, [saveFetcher.state, saveData, stage, revalidate]);

  function handleParse() {
    setParseError(null);
    const parsed = parseResultsText(pasteText);
    if (parsed.length === 0) {
      setParseError("No results found. Check the format and try again.");
      return;
    }

    const resolved: ResolvedRow[] = parsed.map((line) => {
      const match = participantByNameRef.current.get(line.rawName.toLowerCase());
      return {
        placement: line.placement,
        rawName: line.rawName,
        participantId: match ? match.id : null,
      };
    });

    setRows(resolved);
    setStage("preview");
  }

  function setRowParticipant(index: number, participantId: string) {
    setRows((prev) =>
      prev.map((row, i) => (i === index ? { ...row, participantId } : row))
    );
  }

  function handleAddNewParticipant(index: number) {
    setAddingNewFor(index);
    setNewParticipantName(rows[index].rawName);
  }

  function handleCreateParticipant(index: number) {
    if (!newParticipantName.trim()) return;
    const formData = new FormData();
    formData.set("intent", "create-participant");
    formData.set("name", newParticipantName.trim());
    formData.set("sportsSeasonId", sportsSeasonId);
    createParticipantFetcher.submit(formData, { method: "post" });
    pendingNewParticipantRowRef.current = index;
    setAddingNewFor(null);
    setNewParticipantName("");
  }

  function handleConfirm() {
    if (!allResolved || rows.length === 0) return;
    setStage("saving");
    const results = rows
      .filter((r) => r.participantId !== null)
      .map((r) => ({
        participantId: r.participantId as string,
        placement: r.placement,
      }));
    const formData = new FormData();
    formData.set("intent", intent);
    formData.set("results", JSON.stringify(results));
    saveFetcher.submit(formData, { method: "post" });
  }

  const allResolved = rows.every((r) => r.participantId !== null);

  if (successMessage) {
    return (
      <Card className="border-emerald-500/30">
        <CardContent className="pt-6">
          <div className="flex items-center gap-2 text-emerald-500">
            <CheckCircle2 className="h-4 w-4" />
            <span className="text-sm font-medium">{successMessage}</span>
            <Button
              variant="ghost"
              size="sm"
              className="ml-auto"
              onClick={() => setSuccessMessage(null)}
            >
              Import more
            </Button>
          </div>
        </CardContent>
      </Card>
    );
  }

  // Participants available for mapping — exclude those already in saved results
  // (but include any that are currently resolved in this batch, to allow re-use)
  const resolvedIds = new Set(rows.map((r) => r.participantId).filter(Boolean) as string[]);
  const availableParticipants = participantsRef.current.filter(
    (p) => !existingResultParticipantIds.has(p.id) || resolvedIds.has(p.id)
  );

  return (
    <Card>
      <CardHeader>
        <CardTitle>
          <Trophy className="inline mr-2 h-4 w-4" />
          Batch Paste Results
        </CardTitle>
        <CardDescription>
          Paste a ranked results list to import all placements at once. Format:{" "}
          <code className="text-xs bg-muted px-1 py-0.5 rounded">
            1. Player Name
          </code>{" "}
          — use{" "}
          <code className="text-xs bg-muted px-1 py-0.5 rounded">T3</code> or
          repeat a rank for ties.
        </CardDescription>
      </CardHeader>
      <CardContent>
        {stage === "idle" && (
          <div className="space-y-4">
            <Textarea
              value={pasteText}
              onChange={(e) => setPasteText(e.target.value)}
              placeholder={
                "1. Gerwyn Price\n2. Luke Littler\nT3. Michael van Gerwen\nT3. Peter Wright\n5. Damon Heta"
              }
              rows={10}
              className="font-mono text-sm"
            />
            {parseError && (
              <p className="text-sm text-destructive">{parseError}</p>
            )}
            <Button
              onClick={handleParse}
              disabled={!pasteText.trim()}
              className="w-full"
            >
              Parse Results
            </Button>
          </div>
        )}

        {(stage === "preview" || stage === "saving") && (
          <div className="space-y-4">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-24">Placement</TableHead>
                  <TableHead>Parsed Name</TableHead>
                  <TableHead>Matched Participant</TableHead>
                  <TableHead className="w-20">Status</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {rows.map((row, index) => {
                  const isTied =
                    rows.filter((r) => r.placement === row.placement).length >
                    1;

                  return (
                    <TableRow key={`${row.placement}-${row.rawName}`}>
                      <TableCell>
                        <div className="flex items-center gap-1">
                          <span className="font-semibold">{row.placement}</span>
                          {isTied && (
                            <Badge
                              variant="outline"
                              className="text-xs px-1 py-0"
                            >
                              T
                            </Badge>
                          )}
                        </div>
                      </TableCell>
                      <TableCell className="text-muted-foreground text-sm">
                        {row.rawName}
                      </TableCell>
                      <TableCell>
                        {row.participantId ? (
                          <span className="text-sm text-emerald-600 dark:text-emerald-400 font-medium">
                            {participantsRef.current.find(
                              (p) => p.id === row.participantId
                            )?.name ?? row.rawName}
                          </span>
                        ) : addingNewFor === index ? (
                          <div className="flex items-center gap-2">
                            <Input
                              value={newParticipantName}
                              onChange={(e) =>
                                setNewParticipantName(e.target.value)
                              }
                              className="h-8 text-sm"
                              placeholder="Participant name"
                            />
                            <Button
                              size="sm"
                              className="h-8"
                              onClick={() => handleCreateParticipant(index)}
                              disabled={!newParticipantName.trim() || createParticipantFetcher.state !== "idle"}
                            >
                              Add
                            </Button>
                            <Button
                              size="sm"
                              variant="ghost"
                              className="h-8"
                              onClick={() => setAddingNewFor(null)}
                            >
                              Cancel
                            </Button>
                          </div>
                        ) : (
                          <Select
                            onValueChange={(val) => {
                              if (val === "__add_new__") {
                                handleAddNewParticipant(index);
                              } else {
                                setRowParticipant(index, val);
                              }
                            }}
                          >
                            <SelectTrigger className="h-8 text-sm">
                              <SelectValue placeholder="Select participant…" />
                            </SelectTrigger>
                            <SelectContent>
                              {availableParticipants.map((p) => (
                                <SelectItem key={p.id} value={p.id}>
                                  {p.name}
                                </SelectItem>
                              ))}
                              <SelectItem value="__add_new__">
                                + Add new participant…
                              </SelectItem>
                            </SelectContent>
                          </Select>
                        )}
                      </TableCell>
                      <TableCell>
                        {row.participantId ? (
                          <Badge className="bg-emerald-500 text-white text-xs">
                            ✓
                          </Badge>
                        ) : (
                          <Badge variant="destructive" className="text-xs">
                            !
                          </Badge>
                        )}
                      </TableCell>
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>

            {saveData?.error && (
              <p className="text-sm text-destructive">{saveData.error}</p>
            )}
            {createData?.error && (
              <p className="text-sm text-destructive">{createData.error}</p>
            )}

            <div className="flex gap-2">
              <Button
                variant="outline"
                onClick={() => setStage("idle")}
                disabled={stage === "saving"}
              >
                Back
              </Button>
              <Button
                onClick={handleConfirm}
                disabled={!allResolved || stage === "saving"}
                className="flex-1"
              >
                {stage === "saving" ? (
                  "Saving…"
                ) : (
                  <>
                    <CheckCircle2 className="mr-2 h-4 w-4" />
                    Confirm & Save All ({rows.length} result
                    {rows.length === 1 ? "" : "s"})
                  </>
                )}
              </Button>
            </div>
          </div>
        )}
      </CardContent>
    </Card>
  );
}
