"use client";

import { useEffect, useMemo, useRef, useState } from "react";
import { useMutation, useQuery } from "convex/react";
import { FunctionReturnType } from "convex/server";
import {
  CalendarClock,
  Clock3,
  MapPin,
  Pencil,
  Play,
  Plus,
  ShieldCheck,
} from "lucide-react";

import { api } from "@/convex/_generated/api";
import { Id } from "@/convex/_generated/dataModel";
import { campaignFormDefaults } from "@/lib/campaign-form";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
  Card,
  CardDescription,
  CardHeader,
  CardTitle,
} from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton";
import { Switch } from "@/components/ui/switch";
import { CampaignFormDialog } from "@/components/campaigns/campaign-form-dialog";
import { cn } from "@/lib/utils";

type CampaignsListResult = FunctionReturnType<typeof api.campaigns.list>;
type CampaignRunsListResult = FunctionReturnType<typeof api.runs.list>;
type CampaignRow = NonNullable<CampaignsListResult>[number];
type CampaignRunRow = NonNullable<CampaignRunsListResult>[number];

type RecurrenceLabel = Record<CampaignRow["recurrence"], string>;
type CurrentRunStatusLabel = {
  [key: string]: string;
};

const recurrenceLabel: RecurrenceLabel = {
  manual: "manuell",
  daily: "täglich",
  weekly: "wöchentlich",
  monthly: "monatlich",
};

const statusLabel: CurrentRunStatusLabel = {
  running: "Läuft",
  pending: "Ausstehend",
  succeeded: "Erledigt",
  failed: "Fehlgeschlagen",
  canceled: "Abgebrochen",
  idle: "Leerlauf",
  paused: "Pausiert",
};

const stepLabel: Record<string, string> = {
  campaign_cron_queued: "Cron geplant",
  campaign_cron_skipped: "Cron übersprungen",
  campaign_cron_stale_pending: "Timeout bereinigt",
  lead_discovery: "Lead-Recherche",
};

const dateFormatter = new Intl.DateTimeFormat("de-DE", {
  dateStyle: "short",
  timeStyle: "short",
});

function formatDateTime(value?: number | null): string {
  if (!value) {
    return "Nicht gesetzt";
  }

  return dateFormatter.format(new Date(value));
}

const formPayloadFromCampaign = (campaign?: CampaignRow | null) => {
  if (!campaign) {
    return campaignFormDefaults;
  }

  return {
    status: campaign.status,
    categoryMode: campaign.categoryMode,
    recurrence: campaign.recurrence,
    radiusKm: campaign.radiusKm,
    maxNewLeadsPerRun: campaign.maxNewLeadsPerRun,
    maxAuditsPerRun: campaign.maxAuditsPerRun,
    name: campaign.name,
    category: campaign.category,
    customSearchTerm: campaign.customSearchTerm ?? "",
    postalCode: campaign.postalCode,
  };
};

const formatNiche = (campaign: CampaignRow): string => {
  if (campaign.category !== "Anderes") {
    return campaign.category;
  }

  return campaign.customSearchTerm?.trim()
    ? `${campaign.category}: ${campaign.customSearchTerm}`
    : campaign.category;
};

const formatRunStatus = (value: string): string => {
  return statusLabel[value] ?? value;
};

const getRunStatusClassName = (value: string): string => {
  if (value === "running" || value === "pending") {
    return "evidence-surface border-transparent";
  }

  if (value === "succeeded") {
    return "safe-surface border-transparent";
  }

  if (value === "failed" || value === "canceled") {
    return "border-transparent bg-[var(--danger-soft)] text-destructive";
  }

  return "border-border/75 bg-muted/55 text-muted-foreground";
};

const getRunStepClassName = (value?: string | null): string => {
  if (value === "campaign_cron_skipped" || value === "campaign_cron_stale_pending") {
    return "review-surface border-transparent";
  }

  if (value === "lead_discovery" || value === "campaign_cron_queued") {
    return "evidence-surface border-transparent";
  }

  return "border-border/75 bg-background/60";
};

export function CampaignsBoard() {
  const campaigns = useQuery(api.campaigns.list, { limit: 100 });
  const recentCampaignRuns = useQuery(api.runs.list, {
    limit: 8,
    type: "campaign",
  });
  const createCampaign = useMutation(api.campaigns.create);
  const updateCampaign = useMutation(api.campaigns.update);
  const setStatus = useMutation(api.campaigns.setStatus);
  const requestRun = useMutation(api.campaigns.requestRun);

  const [editingCampaign, setEditingCampaign] = useState<CampaignRow | null>(null);
  const [isFormOpen, setIsFormOpen] = useState(false);
  const [actionBusyId, setActionBusyId] = useState<Id<"campaigns"> | null>(null);
  const [actionLabel, setActionLabel] = useState<string | null>(null);
  const [formError, setFormError] = useState<string | null>(null);
  const [rowError, setRowError] = useState<string | null>(null);
  const actionLabelTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const clearActionLabelTimer = () => {
    if (actionLabelTimerRef.current) {
      clearTimeout(actionLabelTimerRef.current);
      actionLabelTimerRef.current = null;
    }
  };

  const setActionLabelWithTimeout = (
    label: string,
    clearAfterMs = 1200,
  ) => {
    clearActionLabelTimer();
    setActionLabel(label);

    if (clearAfterMs > 0) {
      actionLabelTimerRef.current = setTimeout(() => setActionLabel(null), clearAfterMs);
    }
  };

  useEffect(() => {
    return () => {
      clearActionLabelTimer();
    };
  }, []);

  const campaignsSorted = useMemo(() => {
    if (!campaigns) {
      return [];
    }

    return [...campaigns].sort((a, b) => b.createdAt - a.createdAt);
  }, [campaigns]);

  const visibleRuns = useMemo<CampaignRunRow[]>(() => {
    return recentCampaignRuns ?? [];
  }, [recentCampaignRuns]);

  const activeCampaignCount = campaignsSorted.filter(
    (campaign) => campaign.status === "active",
  ).length;
  const pausedCampaignCount = campaignsSorted.length - activeCampaignCount;
  const nextScheduledCampaign = [...campaignsSorted]
    .filter((campaign) => campaign.nextRunAt)
    .sort((a, b) => (a.nextRunAt ?? Infinity) - (b.nextRunAt ?? Infinity))
    .at(0);

  const closeDialog = () => {
    setEditingCampaign(null);
    setIsFormOpen(false);
    setFormError(null);
  };

  const openCreateDialog = () => {
    setEditingCampaign(null);
    setRowError(null);
    setIsFormOpen(true);
  };

  const openEditDialog = (campaign: CampaignRow) => {
    setEditingCampaign(campaign);
    setRowError(null);
    setIsFormOpen(true);
  };

  const submitCampaign = async (payload: {
    status: CampaignRow["status"];
    categoryMode: CampaignRow["categoryMode"];
    category: string;
    customSearchTerm?: string;
    postalCode: string;
    radiusKm: number;
    maxNewLeadsPerRun: number;
    maxAuditsPerRun: number;
    recurrence: CampaignRow["recurrence"];
    countryCode: "DE";
    country: "Deutschland";
    name: string;
  }) => {
    setActionLabel("Speichere...");
    setFormError(null);
    try {
      if (!editingCampaign) {
        await createCampaign(payload);
      } else {
        await updateCampaign({
          id: editingCampaign._id,
          ...payload,
        });
      }
      setActionLabelWithTimeout("Gespeichert");
      setIsFormOpen(false);
      setEditingCampaign(null);
    } catch {
      setFormError("Speichern fehlgeschlagen.");
      setActionLabelWithTimeout("Fehler", 2000);
    }
  };

  const runCampaign = async (campaign: CampaignRow) => {
    setActionBusyId(campaign._id);
    setRowError(null);
    try {
      await requestRun({ id: campaign._id });
      setActionLabelWithTimeout(`${campaign.name}: Lauf gestartet`);
    } catch {
      setRowError("Kampagne konnte nicht gestartet werden.");
      setActionLabelWithTimeout("Kampagne konnte nicht gestartet werden.", 2400);
    } finally {
      setActionBusyId(null);
    }
  };

  const toggleCampaign = async (campaign: CampaignRow) => {
    const nextStatus = campaign.status === "active" ? "paused" : "active";
    setActionBusyId(campaign._id);
    setRowError(null);
    try {
      await setStatus({ id: campaign._id, status: nextStatus });
      setActionLabelWithTimeout(
        `${campaign.name}: ${nextStatus === "active" ? "Aktiviert" : "Pausiert"}`,
      );
    } catch {
      setRowError("Status konnte nicht geändert werden.");
      setActionLabelWithTimeout("Status konnte nicht geändert werden.", 2400);
    } finally {
      setActionBusyId(null);
    }
  };

  if (campaigns === undefined) {
    return (
      <section className="space-y-3">
        <div className="flex items-center justify-between gap-3">
          <div className="h-7 w-48 rounded-md bg-muted" />
          <div className="h-8 w-24 rounded-md bg-muted" />
        </div>

        <div className="grid gap-3">
          {Array.from({ length: 4 }, (_, index) => (
            <Skeleton className="h-28 rounded-lg" key={index} />
          ))}
        </div>
      </section>
    );
  }

  return (
    <section className="space-y-4">
      <CampaignFormDialog
        campaign={editingCampaign ? formPayloadFromCampaign(editingCampaign) : null}
        open={isFormOpen}
        onOpenChange={closeDialog}
        onSubmit={submitCampaign}
      />

      <div className="agency-panel flex flex-col gap-4 p-4 sm:flex-row sm:items-end sm:justify-between">
        <div>
          <p className="agency-kicker">Controlled Sourcing</p>
          <h1 className="mt-2 font-heading text-3xl font-semibold tracking-normal">
            Kontrollierte Suchläufe
          </h1>
          <p className="mt-2 max-w-2xl text-sm leading-6 text-muted-foreground">
            Kampagnen bleiben bewusst limitiert: Suchgebiet, Cadence, Run-Status
            und manuelle Freigaben stehen vor jeder Outreach-Bewegung.
          </p>
        </div>

        <Button onClick={openCreateDialog} className="justify-start sm:w-auto">
          <Plus className="size-4" />
          Kampagne anlegen
        </Button>
      </div>

      {formError ? <p className="text-sm text-destructive" role="alert">{formError}</p> : null}
      {rowError ? <p className="text-sm text-destructive" role="alert">{rowError}</p> : null}
      {actionLabel ? <p className="text-sm" role="status">{actionLabel}</p> : null}

      <div className="grid gap-4 2xl:grid-cols-[minmax(0,1fr)_21rem]">
        <div className="min-w-0">
          {campaignsSorted.length === 0 ? (
            <Card className="agency-panel">
              <CardHeader>
                <CardTitle>Keine Kampagnen</CardTitle>
                <CardDescription>
                  Lege zuerst eine Kampagne mit Kategorie, PLZ und Limits an.
                </CardDescription>
              </CardHeader>
            </Card>
          ) : (
            <>
              <div className="campaign-ledger hidden 2xl:block">
                <div role="table" aria-label="Kampagnen-Ledger">
                  <div role="rowgroup">
                    <div
                      className="campaign-ledger-row campaign-ledger-header"
                      role="row"
                    >
                      <div role="columnheader">Kampagne</div>
                      <div role="columnheader">Suchgebiet</div>
                      <div role="columnheader">Status</div>
                      <div role="columnheader">Cadence</div>
                      <div role="columnheader">Limits</div>
                      <div role="columnheader">Läufe</div>
                      <div role="columnheader">Run</div>
                      <div role="columnheader">Aktionen</div>
                    </div>
                  </div>
                  <div role="rowgroup">
                    {campaignsSorted.map((campaign) => {
                      const campaignTitleId = `campaign-title-${campaign._id}`;
                      const isBusy = actionBusyId === campaign._id;
                      const isActive = campaign.status === "active";

                      return (
                        <div
                          aria-labelledby={campaignTitleId}
                          className="campaign-ledger-row"
                          key={campaign._id}
                          role="row"
                        >
                          <div className="min-w-0" role="cell">
                            <h2
                              className="truncate font-heading text-sm font-semibold"
                              id={campaignTitleId}
                            >
                              {campaign.name}
                            </h2>
                            <p className="mt-1 truncate text-xs text-muted-foreground">
                              {formatNiche(campaign)}
                            </p>
                          </div>
                          <div className="grid gap-1 text-sm" role="cell">
                            <span className="inline-flex items-center gap-1 font-medium">
                              <MapPin className="size-3.5 text-primary" />
                              {campaign.postalCode}
                            </span>
                            <span className="text-xs text-muted-foreground">
                              Radius {campaign.radiusKm} km
                            </span>
                          </div>
                          <div className="grid gap-1" role="cell">
                            <label className="inline-flex items-center gap-2 text-sm font-medium">
                              <Switch
                                checked={isActive}
                                onCheckedChange={() => toggleCampaign(campaign)}
                                disabled={isBusy}
                                aria-label={`${campaign.name} Status ändern`}
                              />
                              {isActive ? "Aktiv" : "Pausiert"}
                            </label>
                          </div>
                          <div className="grid gap-1 text-sm" role="cell">
                            <span className="inline-flex items-center gap-1 font-medium">
                              <Clock3 className="size-3.5 text-primary" />
                              {recurrenceLabel[campaign.recurrence]}
                            </span>
                          </div>
                          <div className="grid gap-1 text-sm" role="cell">
                            <span>Lead-Limit: {campaign.maxNewLeadsPerRun}</span>
                            <span>Audit-Limit: {campaign.maxAuditsPerRun}</span>
                          </div>
                          <div className="grid gap-1 text-xs text-muted-foreground" role="cell">
                            <span>Letzter Lauf: {formatDateTime(campaign.lastRunAt)}</span>
                            <span>Nächster Lauf: {formatDateTime(campaign.nextRunAt)}</span>
                          </div>
                          <div className="grid gap-1" role="cell">
                            <Badge
                              className={getRunStatusClassName(
                                campaign.currentRunStatus,
                              )}
                              variant="outline"
                            >
                              {formatRunStatus(campaign.currentRunStatus)}
                            </Badge>
                          </div>
                          <div className="flex flex-wrap items-center justify-end gap-1" role="cell">
                            <Button
                              variant="outline"
                              size="icon-sm"
                              onClick={() => openEditDialog(campaign)}
                              disabled={isBusy}
                              aria-label={`${campaign.name} bearbeiten`}
                            >
                              <Pencil className="size-3.5" />
                            </Button>
                            <Button
                              variant="outline"
                              onClick={() => runCampaign(campaign)}
                              disabled={isBusy}
                              size="sm"
                            >
                              <Play className="size-3.5" />
                              Suchlauf starten
                            </Button>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>
              </div>

              <div className="campaign-mobile-records grid gap-3 2xl:hidden">
                {campaignsSorted.map((campaign) => {
                  const campaignTitleId = `campaign-title-mobile-${campaign._id}`;
                  const isBusy = actionBusyId === campaign._id;
                  const isActive = campaign.status === "active";

                  return (
                    <article
                      aria-labelledby={campaignTitleId}
                      className="campaign-mobile-record"
                      key={campaign._id}
                    >
                      <div className="flex flex-wrap items-start justify-between gap-3">
                        <div className="min-w-0">
                          <h2
                            className="truncate font-heading text-base font-semibold"
                            id={campaignTitleId}
                          >
                            {campaign.name}
                          </h2>
                          <p className="mt-1 text-sm text-muted-foreground">
                            {formatNiche(campaign)} · {campaign.postalCode}
                          </p>
                        </div>
                        <label className="inline-flex items-center gap-2 text-sm font-medium">
                          <Switch
                            checked={isActive}
                            onCheckedChange={() => toggleCampaign(campaign)}
                            disabled={isBusy}
                            aria-label={`${campaign.name} Status ändern`}
                          />
                          {isActive ? "Aktiv" : "Pausiert"}
                        </label>
                      </div>

                      <div className="mt-3 grid gap-2 text-sm sm:grid-cols-2">
                        <p className="rounded-md bg-muted/50 px-3 py-2">
                          Radius {campaign.radiusKm} km · {recurrenceLabel[campaign.recurrence]}
                        </p>
                        <p className="rounded-md bg-muted/50 px-3 py-2">
                          Lead-Limit: {campaign.maxNewLeadsPerRun} · Audit-Limit:{" "}
                          {campaign.maxAuditsPerRun}
                        </p>
                        <p className="rounded-md bg-muted/50 px-3 py-2">
                          Letzter Lauf: {formatDateTime(campaign.lastRunAt)}
                        </p>
                        <p className="rounded-md bg-muted/50 px-3 py-2">
                          Nächster Lauf: {formatDateTime(campaign.nextRunAt)}
                        </p>
                      </div>

                      <div className="mt-3 flex flex-wrap items-center justify-between gap-2">
                        <Badge
                          className={getRunStatusClassName(
                            campaign.currentRunStatus,
                          )}
                          variant="outline"
                        >
                          Run: {formatRunStatus(campaign.currentRunStatus)}
                        </Badge>
                        <div className="flex gap-2">
                          <Button
                            variant="outline"
                            size="sm"
                            onClick={() => openEditDialog(campaign)}
                            disabled={isBusy}
                          >
                            <Pencil className="size-3.5" />
                            Bearbeiten
                          </Button>
                          <Button
                            variant="outline"
                            onClick={() => runCampaign(campaign)}
                            disabled={isBusy}
                            size="sm"
                          >
                            <Play className="size-3.5" />
                            Suchlauf starten
                          </Button>
                        </div>
                      </div>
                    </article>
                  );
                })}
              </div>
            </>
          )}
        </div>

        <aside className="campaign-status-rail agency-panel grid gap-3 p-4">
          <div>
            <p className="agency-kicker">Sourcing Status</p>
            <h2 className="mt-2 font-heading text-lg font-semibold">
              Kampagnenkontrolle
            </h2>
          </div>

          <div className="grid grid-cols-2 gap-2">
            <div className="safe-surface rounded-md p-3">
              <p className="text-2xl font-semibold">{activeCampaignCount}</p>
              <p className="text-xs font-medium">aktiv</p>
            </div>
            <div className="review-surface rounded-md p-3">
              <p className="text-2xl font-semibold">{pausedCampaignCount}</p>
              <p className="text-xs font-medium">pausiert</p>
            </div>
          </div>

          <div className="rounded-md border border-border/75 bg-background/60 p-3 text-sm">
            <p className="inline-flex items-center gap-2 font-semibold">
              <CalendarClock className="size-4 text-primary" />
              Nächster geplanter Lauf
            </p>
            <p className="mt-2 text-muted-foreground">
              {nextScheduledCampaign
                ? `${nextScheduledCampaign.name}: ${formatDateTime(nextScheduledCampaign.nextRunAt)}`
                : "Kein Lauf geplant"}
            </p>
          </div>

          <div className="safe-surface rounded-md p-3 text-sm">
            <p className="inline-flex items-center gap-2 font-semibold">
              <ShieldCheck className="size-4" />
              Versand nur nach Freigabe
            </p>
            <p className="mt-1 text-xs">
              Kampagnen erzeugen Recherche und Audits. Outreach bleibt manuell
              geprüft.
            </p>
          </div>

          <div>
            <div className="flex items-start justify-between gap-3">
              <div>
                <h2 className="font-heading text-base font-semibold">
                  Aktuelle Run-Logs
                </h2>
                <p className="mt-1 text-xs text-muted-foreground">
                  Cron-Skips, Fehler und letzte Kampagnenläufe.
                </p>
              </div>
            </div>
            <div className="mt-3 grid gap-2 text-sm">
              {recentCampaignRuns === undefined ? (
                <Skeleton className="h-16 rounded-lg" />
              ) : visibleRuns.length === 0 ? (
                <p className="text-muted-foreground">
                  Noch keine Kampagnenläufe.
                </p>
              ) : (
                visibleRuns.map((run) => (
                  <div
                    className={cn(
                      "rounded-md border p-3",
                      getRunStatusClassName(run.status),
                      getRunStepClassName(run.currentStep),
                    )}
                    key={run._id}
                  >
                    <div className="flex flex-wrap items-center justify-between gap-2">
                      <p className="font-medium">
                        {formatRunStatus(run.status)}
                      </p>
                      <p className="text-xs text-muted-foreground">
                        {formatDateTime(run.updatedAt)}
                      </p>
                    </div>
                    <p className="mt-1 text-muted-foreground">
                      {stepLabel[run.currentStep ?? ""] ??
                        run.currentStep ??
                        "Schritt offen"}
                    </p>
                    {run.currentStep === "campaign_cron_skipped" ? (
                      <p className="mt-1 text-xs text-muted-foreground">
                        Cron wurde übersprungen, weil bereits ein Agentenlauf
                        aktiv war.
                      </p>
                    ) : null}
                    {run.errorSummary ? (
                      <p className="mt-1 text-xs text-destructive">
                        {run.errorSummary}
                      </p>
                    ) : null}
                  </div>
                ))
              )}
            </div>
          </div>
        </aside>
      </div>
    </section>
  );
}
