import { FormEvent, useMemo, useState } from "react";
import type { Dispatch, SetStateAction } from "react";
import { Pause, Play, Plus, RotateCcw, Square, Upload } from "lucide-react";
import { toast } from "sonner";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { HelpLink } from "@/components/HelpLink";
import { OrganizationSelect } from "@/components/OrganizationSelect";
import { createSession, lookupTicket } from "../api";
import { formatTimer } from "../format";
import { activeElapsedMs, pauseEntry, resumeEntry, ticketPattern, type TimerEntry } from "../timers";
import type { TicketMeta, WorkType } from "../types";

type ManualSessionFormState = {
  ticketNumber: string;
  organizationId: string;
  organizationName: string | null;
  activity: string;
  workType: WorkType;
  day: string;
  startTime: string;
  endTime: string;
};

function currentDay() {
  const now = new Date();
  return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
}

function emptyManualSession(): ManualSessionFormState {
  return {
    ticketNumber: "",
    organizationId: "",
    organizationName: null,
    activity: "",
    workType: "support",
    day: currentDay(),
    startTime: "09:00",
    endTime: "09:30"
  };
}

type FinishedSession = {
  timerId: string;
  ticketNumber: string;
  ticket: TicketMeta | null;
  startedAt: string;
  endedAt: string;
  durationSeconds: number;
  roundedMinutes: number;
};

type TimerPageProps = {
  timers: TimerEntry[];
  setTimers: Dispatch<SetStateAction<TimerEntry[]>>;
  selectedTimerId: string | null;
  setSelectedTimerId: Dispatch<SetStateAction<string | null>>;
  tick: number;
};

export function TimerPage({ timers, setTimers, selectedTimerId, setSelectedTimerId, tick }: TimerPageProps) {
  const [ticketNumber, setTicketNumber] = useState("");
  const [finished, setFinished] = useState<FinishedSession | null>(null);
  const [finishingId, setFinishingId] = useState<string | null>(null);
  const [organizationId, setOrganizationId] = useState("");
  const [organizationName, setOrganizationName] = useState<string | null>(null);
  const [activity, setActivity] = useState("");
  const [workType, setWorkType] = useState<WorkType>("support");
  const [saving, setSaving] = useState(false);
  const [manualSession, setManualSession] = useState<ManualSessionFormState>(() => emptyManualSession());
  const [savingManualSession, setSavingManualSession] = useState(false);

  const selectedTimer = timers.find((timer) => timer.id === selectedTimerId) ?? timers[0] ?? null;
  const elapsedSeconds = useMemo(() => Math.floor(activeElapsedMs(selectedTimer, tick) / 1000), [selectedTimer, tick]);
  const isValidTicket = ticketPattern.test(ticketNumber);
  const runningTimer = timers.find((timer) => timer.phase === "running") ?? null;

  async function addTimer() {
    if (!isValidTicket) {
      toast.error("Ticketnummer prüfen", {
        description: "Das Format muss Ticket#XXXXXX sein."
      });
      return;
    }

    if (timers.some((timer) => timer.ticketNumber === ticketNumber)) {
      toast.error("Timer existiert bereits", {
        description: "Für dieses Ticket läuft oder pausiert schon ein Timer."
      });
      return;
    }

    const now = Date.now();
    const ticketResult = await lookupTicket(ticketNumber).catch(() => ({ ticket: null }));
    const newTimer: TimerEntry = {
      id: crypto.randomUUID(),
      ticketNumber,
      organizationName: ticketResult.ticket?.organization_name ?? ticketResult.ticket?.customer_name ?? null,
      workType: ticketResult.ticket?.work_type ?? null,
      ticketLookupDone: true,
      startedAt: now,
      pausedTotalMs: 0,
      pausedAt: null,
      phase: "running"
    };

    setTimers((current) => [...current.map((timer) => pauseEntry(timer, now)), newTimer]);
    setSelectedTimerId(newTimer.id);
    setTicketNumber("");
  }

  function activateTimer(timerId: string) {
    const now = Date.now();
    setTimers((current) =>
      current.map((timer) => {
        if (timer.id === timerId) {
          return resumeEntry(timer, now);
        }

        return pauseEntry(timer, now);
      })
    );
    setSelectedTimerId(timerId);
  }

  function pauseTimer(timerId: string) {
    const now = Date.now();
    setTimers((current) => current.map((timer) => (timer.id === timerId ? pauseEntry(timer, now) : timer)));
    setSelectedTimerId(timerId);
  }

  function resetTimer(timerId: string) {
    setTimers((current) => current.filter((timer) => timer.id !== timerId));
  }

  async function finishTimer(timerId: string) {
    const timer = timers.find((entry) => entry.id === timerId);

    if (!timer) {
      return;
    }

    const now = Date.now();
    const stoppedTimer = pauseEntry(timer, now);
    const durationSeconds = Math.floor(activeElapsedMs(stoppedTimer, now) / 1000);
    const roundedMinutes = Math.max(1, Math.round(durationSeconds / 60));

    setTimers((current) => current.map((entry) => (entry.id === timerId ? pauseEntry(entry, now) : entry)));
    setSelectedTimerId(timer.id);
    setFinishingId(timer.id);

    try {
      const result = await lookupTicket(timer.ticketNumber);
      const ticket = result.ticket;

      setOrganizationId(ticket?.organization_id ?? "");
      setOrganizationName(ticket?.organization_name ?? null);
      setWorkType(ticket?.work_type ?? "support");
      setActivity("");
      setFinished({
        timerId: timer.id,
        ticketNumber: timer.ticketNumber,
        ticket,
        startedAt: new Date(stoppedTimer.startedAt).toISOString(),
        endedAt: new Date(now).toISOString(),
        durationSeconds,
        roundedMinutes
      });
    } catch (error) {
      toast.error("Ticket konnte nicht geprüft werden", {
        description: error instanceof Error ? error.message : "Unbekannter Fehler"
      });
    } finally {
      setFinishingId(null);
    }
  }

  async function submitSession(event: FormEvent) {
    event.preventDefault();

    if (!finished) {
      return;
    }

    const existingTicketHasDefaults = Boolean(finished.ticket?.organization_id && finished.ticket?.work_type);
    const effectiveOrganizationId = existingTicketHasDefaults ? finished.ticket!.organization_id! : organizationId;
    const effectiveWorkType = existingTicketHasDefaults ? finished.ticket!.work_type! : workType;

    if (!effectiveOrganizationId) {
      toast.error("Organisation wählen", {
        description: "Neue Sessions können nur mit einer synchronisierten Organisation gespeichert werden."
      });
      return;
    }

    setSaving(true);

    try {
      await createSession({
        ticketNumber: finished.ticketNumber,
        startedAt: finished.startedAt,
        endedAt: finished.endedAt,
        durationSeconds: finished.durationSeconds,
        organizationId: effectiveOrganizationId,
        activity,
        workType: effectiveWorkType
      });

      toast.success("Session gespeichert", {
        description: `${finished.ticketNumber} wurde mit ${finished.roundedMinutes} Minute(n) erfasst.`
      });
      setTimers((current) => current.filter((timer) => timer.id !== finished.timerId));
      setFinished(null);
      setOrganizationId("");
      setOrganizationName(null);
      setActivity("");
      setWorkType("support");
    } catch (error) {
      toast.error("Speichern fehlgeschlagen", {
        description: error instanceof Error ? error.message : "Unbekannter Fehler"
      });
    } finally {
      setSaving(false);
    }
  }

  async function submitManualSession(event: FormEvent) {
    event.preventDefault();

    if (!ticketPattern.test(manualSession.ticketNumber)) {
      toast.error("Ticketnummer prüfen", {
        description: "Das Format muss Ticket#XXXXXX sein."
      });
      return;
    }

    if (!manualSession.organizationId) {
      toast.error("Organisation wählen");
      return;
    }

    const startedAt = new Date(`${manualSession.day}T${manualSession.startTime}:00`);
    const endedAt = new Date(`${manualSession.day}T${manualSession.endTime}:00`);

    if (Number.isNaN(startedAt.getTime()) || Number.isNaN(endedAt.getTime())) {
      toast.error("Datum oder Uhrzeit prüfen");
      return;
    }

    if (endedAt <= startedAt) {
      toast.error("Ende muss nach Beginn liegen");
      return;
    }

    const durationSeconds = Math.floor((endedAt.getTime() - startedAt.getTime()) / 1000);

    setSavingManualSession(true);

    try {
      await createSession({
        ticketNumber: manualSession.ticketNumber,
        organizationId: manualSession.organizationId,
        activity: manualSession.activity,
        workType: manualSession.workType,
        startedAt: startedAt.toISOString(),
        endedAt: endedAt.toISOString(),
        durationSeconds
      });
      toast.success("Session nachgetragen", {
        description: "Der Eintrag ist in deiner Auswertung offen."
      });
      setManualSession({
        ...emptyManualSession(),
        day: manualSession.day
      });
    } catch (error) {
      toast.error("Session konnte nicht nachgetragen werden", {
        description: error instanceof Error ? error.message : "Unbekannter Fehler"
      });
    } finally {
      setSavingManualSession(false);
    }
  }

  return (
    <div className="space-y-4">
      <section className="space-y-4">
        <div className="flex flex-col gap-2 sm:flex-row sm:items-end sm:justify-between">
          <div>
            <h2 className="text-xl font-semibold tracking-normal sm:text-2xl">Timer</h2>
            <p className="text-sm text-muted-foreground">Mehrere Tickets vorbereiten, aber immer nur eine Session aktiv messen.</p>
          </div>
          {runningTimer ? <Badge variant="success">Aktiv: {runningTimer.ticketNumber}</Badge> : null}
          {!runningTimer && timers.length > 0 ? <Badge variant="warning">Alle pausiert</Badge> : null}
          {timers.length === 0 ? <Badge variant="info">Kein Timer aktiv</Badge> : null}
        </div>

        <Card className="overflow-hidden">
          <CardHeader className="border-b bg-muted/30 p-4">
            <div className="flex items-start justify-between gap-3">
              <div>
                <CardTitle>Neuen Timer starten</CardTitle>
                <CardDescription>Ein neuer Timer startet sofort und pausiert alle anderen Timer automatisch.</CardDescription>
              </div>
              <HelpLink anchor="timer" label="Hilfe zu Timern" />
            </div>
          </CardHeader>
          <CardContent className="grid gap-3 p-4 sm:grid-cols-[minmax(220px,320px)_auto] sm:items-end">
            <div className="space-y-2">
              <label className="text-sm font-medium" htmlFor="ticket-number">
                Ticketnummer
              </label>
              <Input
                id="ticket-number"
                placeholder="Ticket#123456"
                value={ticketNumber}
                onChange={(event) => setTicketNumber(event.currentTarget.value)}
                onKeyDown={(event) => {
                  if (event.key === "Enter") {
                    void addTimer();
                  }
                }}
              />
              {ticketNumber.length > 0 && !isValidTicket ? <p className="text-xs text-destructive">Format: Ticket#XXXXXX</p> : null}
            </div>
            <Button onClick={() => void addTimer()}>
              <Plus className="size-4" />
              Timer starten
            </Button>
          </CardContent>
        </Card>

        <Card className="overflow-hidden">
          <CardHeader className="border-b bg-muted/30 p-4">
            <div className="flex items-start justify-between gap-3">
              <div>
                <CardTitle>{selectedTimer ? selectedTimer.ticketNumber : "Keine Session ausgewählt"}</CardTitle>
                <CardDescription>
                  {selectedTimer
                    ? selectedTimer.organizationName
                      ? `${selectedTimer.organizationName}${selectedTimer.workType ? ` · ${selectedTimer.workType === "support" ? "Support" : "Consulting"}` : ""}`
                      : "Beim Umschalten wird dieser Timer aktiviert und alle anderen werden pausiert."
                    : "Starte einen Timer, um eine Session zu erfassen."}
                </CardDescription>
              </div>
              <HelpLink anchor="timer" label="Hilfe zum Timerstatus" />
            </div>
          </CardHeader>
          <CardContent className="space-y-4 p-4">
            <div className="rounded-lg border bg-background p-4 sm:p-5">
              <p className="mb-2 text-sm font-medium text-muted-foreground">Gemessene Arbeitszeit</p>
              <p className="font-mono text-4xl font-bold leading-none tracking-normal sm:text-6xl">
                {formatTimer(elapsedSeconds)}
              </p>
            </div>

            <div className="grid grid-cols-2 gap-2 sm:flex sm:flex-wrap">
              {selectedTimer?.phase === "running" ? (
                <Button variant="secondary" disabled={!selectedTimer} onClick={() => selectedTimer && pauseTimer(selectedTimer.id)}>
                  <Pause className="size-4" />
                  Pausieren
                </Button>
              ) : (
                <Button disabled={!selectedTimer} onClick={() => selectedTimer && activateTimer(selectedTimer.id)}>
                  <Play className="size-4" />
                  Aktivieren
                </Button>
              )}

              <Button variant="destructive" disabled={!selectedTimer || finishingId === selectedTimer?.id} onClick={() => selectedTimer && void finishTimer(selectedTimer.id)}>
                <Square className="size-4" />
                {finishingId === selectedTimer?.id ? "Prüft..." : "Beenden"}
              </Button>
              <Button variant="ghost" disabled={!selectedTimer} onClick={() => selectedTimer && resetTimer(selectedTimer.id)}>
                <RotateCcw className="size-4" />
                Entfernen
              </Button>
            </div>
          </CardContent>
        </Card>

        <Card className="overflow-hidden">
          <CardHeader className="border-b bg-muted/30 p-4">
            <div className="flex items-start justify-between gap-3">
              <div>
                <CardTitle>Session nachtragen</CardTitle>
                <CardDescription>Vergessene Zeiten für deinen eigenen Account manuell erfassen.</CardDescription>
              </div>
              <HelpLink anchor="session-nachtragen" label="Hilfe zum Nachtragen von Sessions" />
            </div>
          </CardHeader>
          <CardContent className="p-4">
            <form className="space-y-4" onSubmit={submitManualSession}>
              <div className="grid gap-3 lg:grid-cols-[160px_minmax(180px,1fr)_150px]">
                <div className="space-y-2">
                  <label className="text-sm font-medium" htmlFor="manual-ticket-number">Ticket</label>
                  <Input
                    id="manual-ticket-number"
                    placeholder="Ticket#123456"
                    value={manualSession.ticketNumber}
                    onChange={(event) => setManualSession({ ...manualSession, ticketNumber: event.currentTarget.value })}
                    required
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium">Organisation</label>
                  <OrganizationSelect
                    value={manualSession.organizationId}
                    selectedName={manualSession.organizationName}
                    onChange={(organization) =>
                      setManualSession({
                        ...manualSession,
                        organizationId: organization.id,
                        organizationName: organization.name
                      })
                    }
                    required
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium" htmlFor="manual-work-type">Art</label>
                  <select
                    id="manual-work-type"
                    className="h-9 w-full rounded-lg border border-input bg-background px-2 text-sm focus-visible:outline-none focus-visible:ring-3 focus-visible:ring-ring/50"
                    value={manualSession.workType}
                    onChange={(event) => setManualSession({ ...manualSession, workType: event.currentTarget.value as WorkType })}
                  >
                    <option value="support">Support</option>
                    <option value="consulting">Consulting</option>
                  </select>
                </div>
              </div>

              <div className="grid gap-3 lg:grid-cols-[160px_120px_120px_minmax(220px,1fr)_auto] lg:items-end">
                <div className="space-y-2">
                  <label className="text-sm font-medium" htmlFor="manual-day">Datum</label>
                  <Input
                    id="manual-day"
                    type="date"
                    value={manualSession.day}
                    onChange={(event) => setManualSession({ ...manualSession, day: event.currentTarget.value })}
                    required
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium" htmlFor="manual-start">Von</label>
                  <Input
                    id="manual-start"
                    type="time"
                    value={manualSession.startTime}
                    onChange={(event) => setManualSession({ ...manualSession, startTime: event.currentTarget.value })}
                    required
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium" htmlFor="manual-end">Bis</label>
                  <Input
                    id="manual-end"
                    type="time"
                    value={manualSession.endTime}
                    onChange={(event) => setManualSession({ ...manualSession, endTime: event.currentTarget.value })}
                    required
                  />
                </div>
                <div className="space-y-2">
                  <label className="text-sm font-medium" htmlFor="manual-activity">Tätigkeit</label>
                  <Textarea
                    id="manual-activity"
                    className="min-h-20"
                    value={manualSession.activity}
                    onChange={(event) => setManualSession({ ...manualSession, activity: event.currentTarget.value })}
                    required
                  />
                </div>
                <Button type="submit" disabled={savingManualSession}>
                  <Upload className="size-4" />
                  {savingManualSession ? "Speichert..." : "Nachtragen"}
                </Button>
              </div>
            </form>
          </CardContent>
        </Card>

      </section>

      <Dialog open={Boolean(finished)} onOpenChange={(open) => !open && setFinished(null)}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Session abschließen</DialogTitle>
            <DialogDescription>
              {finished?.ticketNumber}: {finished?.roundedMinutes} Minute(n), Pausen bereits abgezogen.
            </DialogDescription>
          </DialogHeader>

          <form className="space-y-4" onSubmit={submitSession}>
            {finished?.ticket?.organization_id && finished.ticket.work_type ? (
              <div className="rounded-lg border bg-muted/40 p-3 text-sm">
                <p className="font-medium">{finished.ticket.organization_name ?? finished.ticket.customer_name}</p>
                <p className="text-muted-foreground">{finished.ticket.work_type === "support" ? "Support" : "Consulting"} wurde vom bestehenden Ticket übernommen.</p>
              </div>
            ) : (
              <div className="space-y-2">
                <label className="text-sm font-medium" htmlFor="organization">
                  Organisation
                </label>
                {finished?.ticket?.customer_name && !finished.ticket.organization_id ? (
                  <p className="text-xs text-muted-foreground">Bisheriger Freitext: {finished.ticket.customer_name}</p>
                ) : null}
                <OrganizationSelect
                  value={organizationId}
                  selectedName={organizationName}
                  onChange={(organization) => {
                    setOrganizationId(organization.id);
                    setOrganizationName(organization.name);
                  }}
                  required
                />
              </div>
            )}
            <div className="space-y-2">
              <label className="text-sm font-medium" htmlFor="activity">
                Tätigkeit
              </label>
              <Textarea id="activity" value={activity} onChange={(event) => setActivity(event.currentTarget.value)} required />
            </div>
            {finished?.ticket?.organization_id && finished.ticket.work_type ? null : (
              <div className="space-y-2">
                <label className="text-sm font-medium" htmlFor="work-type">
                  Art
                </label>
                <select
                  id="work-type"
                  className="h-10 w-full rounded-md border border-input bg-background px-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                  value={workType}
                  onChange={(event) => setWorkType(event.currentTarget.value as WorkType)}
                >
                  <option value="support">Support</option>
                  <option value="consulting">Consulting</option>
                </select>
              </div>
            )}
            <div className="flex justify-end">
              <Button type="submit" disabled={saving}>
                <Upload className="size-4" />
                {saving ? "Speichern..." : "Eintrag speichern"}
              </Button>
            </div>
          </form>
        </DialogContent>
      </Dialog>
    </div>
  );
}
