"use client";

import { useMemo, useState } from "react";

import { useMutation, useQuery } from "convex/react";
import type { FunctionReturnType } from "convex/server";
import { ChevronDown, ChevronRight, ExternalLink, MailCheck, Save } from "lucide-react";
import Link from "next/link";

import { api } from "@/convex/_generated/api";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Skeleton } from "@/components/ui/skeleton";
import { cn } from "@/lib/utils";

type ReviewWorkspaceListResult = FunctionReturnType<
  typeof api.outreach.listReviewWorkspace
>;
type ReviewWorkspaceItem = NonNullable<ReviewWorkspaceListResult>[number];
type UsedSkill = ReviewWorkspaceItem["usedSkills"][number];

type DraftState = {
  auditBody: string;
  auditSummary: string;
  emailBody: string;
  emailSubject: string;
  followUpDraft: string;
  phoneScript: string;
};

const emptyDraft: DraftState = {
  auditBody: "",
  auditSummary: "",
  emailBody: "",
  emailSubject: "",
  followUpDraft: "",
  phoneScript: "",
};

const textAreaClassName =
  "min-h-24 w-full rounded-md border border-input bg-background px-2.5 py-2 text-sm text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50";

function getDraft(record: ReviewWorkspaceItem): DraftState {
  const outreach = record.latestOutreach;

  return {
    auditBody: record.audit?.publicBody ?? "",
    auditSummary: record.audit?.publicSummary ?? "",
    emailBody: outreach?.emailBody ?? "",
    emailSubject: outreach?.emailSubject ?? "",
    followUpDraft: outreach?.followUpDraft ?? "",
    phoneScript: outreach?.phoneScript ?? "",
  };
}

function compactText(value?: string | null, fallback = "Offen") {
  const trimmed = value?.trim();
  return trimmed ? trimmed : fallback;
}

function formatStrategy(strategy?: string | null) {
  const labels: Record<string, string> = {
    call_first: "Erst anrufen",
    defer: "Zurückstellen",
    do_not_contact: "Nicht kontaktieren",
    email_first: "Erst E-Mail",
  };

  return strategy ? labels[strategy] ?? strategy : "Strategie offen";
}

function formatRaw(value: unknown) {
  if (value === undefined || value === null) {
    return "Keine Rohdaten vorhanden.";
  }

  return JSON.stringify(value, null, 2);
}

function skillLabel(skill: UsedSkill) {
  const name = compactText(skill?.name, "Skill");
  return skill.category ? `${name} · ${skill.category}` : name;
}

function DetailToggle({
  isOpen,
  label,
  onClick,
}: {
  isOpen: boolean;
  label: string;
  onClick: () => void;
}) {
  const Icon = isOpen ? ChevronDown : ChevronRight;

  return (
    <Button
      aria-expanded={isOpen}
      onClick={onClick}
      size="sm"
      type="button"
      variant="outline"
    >
      <Icon className="size-3.5" />
      {label}
    </Button>
  );
}

function FieldPair({ label, value }: { label: string; value?: string | null }) {
  return (
    <div className="min-w-0">
      <dt className="text-xs font-medium text-muted-foreground">{label}</dt>
      <dd className="mt-1 break-words text-sm">{compactText(value)}</dd>
    </div>
  );
}

function WorkspaceLoading() {
  return (
    <section className="space-y-4">
      <header className="space-y-2">
        <p className="text-sm text-muted-foreground">Interne Outreach-Prüfung</p>
        <h1 className="text-2xl font-semibold tracking-normal">Review Workspace</h1>
      </header>
      <div className="space-y-3">
        {Array.from({ length: 3 }, (_, index) => (
          <Skeleton className="h-56 rounded-lg" key={index} />
        ))}
      </div>
    </section>
  );
}

export function OutreachReviewWorkspace() {
  const records = useQuery(api.outreach.listReviewWorkspace, { limit: 100 });
  const saveReviewDraft = useMutation(api.outreach.saveReviewDraft);
  const approveEmailDraft = useMutation(api.outreach.approveEmailDraft);
  const savePublicAuditContent = useMutation(api.audits.savePublicAuditContent);
  const publishPublicAudit = useMutation(api.audits.publishPublicAudit);

  const [drafts, setDrafts] = useState<Record<string, DraftState>>({});
  const [openSources, setOpenSources] = useState<Record<string, boolean>>({});
  const [openRaw, setOpenRaw] = useState<Record<string, boolean>>({});
  const [busyAction, setBusyAction] = useState<string | null>(null);
  const [notice, setNotice] = useState<string | null>(null);

  const rows = useMemo(() => records ?? [], [records]);

  if (records === undefined) {
    return <WorkspaceLoading />;
  }

  if (rows.length === 0) {
    return (
      <section className="space-y-4">
        <header className="space-y-2">
          <p className="text-sm text-muted-foreground">Interne Outreach-Prüfung</p>
          <h1 className="text-2xl font-semibold tracking-normal">Review Workspace</h1>
        </header>
        <Card>
          <CardContent className="p-4">
            <p className="text-sm font-medium">Keine offenen Reviews</p>
            <p className="mt-1 text-sm text-muted-foreground">
              Sobald Audit- und Outreach-Entwürfe bereitstehen, erscheinen sie hier.
            </p>
          </CardContent>
        </Card>
      </section>
    );
  }

  const updateDraft = (
    id: string,
    field: keyof DraftState,
    value: string,
  ) => {
    const record = rows.find((row) => row.id === id);

    setDrafts((current) => ({
      ...current,
      [id]: {
        ...(current[id] ?? (record ? getDraft(record) : emptyDraft)),
        [field]: value,
      },
    }));
  };

  const saveAudit = async (record: ReviewWorkspaceItem) => {
    const auditId = record.audit?._id;
    if (!auditId) {
      setNotice("Audit kann ohne Audit-ID nicht gespeichert werden.");
      return;
    }

    setBusyAction(`${record.id}:audit-save`);
    setNotice(null);
    try {
      const draft = drafts[record.id] ?? getDraft(record);
      await savePublicAuditContent({
        id: auditId,
        publicBody: draft.auditBody,
        publicSummary: draft.auditSummary,
      });
      setNotice("Audit-Änderungen gespeichert.");
    } catch {
      setNotice("Audit-Änderungen konnten nicht gespeichert werden.");
    } finally {
      setBusyAction(null);
    }
  };

  const publishAudit = async (record: ReviewWorkspaceItem) => {
    const auditId = record.audit?._id;
    if (!auditId) {
      setNotice("Audit kann ohne Audit-ID nicht veröffentlicht werden.");
      return;
    }

    setBusyAction(`${record.id}:audit-publish`);
    setNotice(null);
    try {
      const draft = drafts[record.id] ?? getDraft(record);
      await savePublicAuditContent({
        id: auditId,
        publicBody: draft.auditBody,
        publicSummary: draft.auditSummary,
      });
      await publishPublicAudit({ id: auditId });
      setNotice("Audit veröffentlicht.");
    } catch {
      setNotice("Audit konnte nicht veröffentlicht werden.");
    } finally {
      setBusyAction(null);
    }
  };

  const saveOutreach = async (record: ReviewWorkspaceItem) => {
    const outreach = record.latestOutreach;
    if (!outreach) {
      setNotice("Outreach-Entwurf kann ohne Outreach-ID nicht gespeichert werden.");
      return;
    }

    const draft = drafts[record.id] ?? getDraft(record);
    const strategy = outreach.strategy;
    const hasCallablePhone =
      Boolean(record.lead?.phone) &&
      (strategy === "call_first" ||
        record.lead?.contactStatus === "missing_contact");

    setBusyAction(`${record.id}:outreach-save`);
    setNotice(null);
    try {
      await saveReviewDraft({
        id: outreach._id,
        strategy,
        emailBody: draft.emailBody,
        emailSubject: draft.emailSubject,
        followUpDraft: draft.followUpDraft,
        ...(hasCallablePhone ? { phoneScript: draft.phoneScript } : {}),
      });
      setNotice("Outreach-Entwurf gespeichert.");
    } catch {
      setNotice("Outreach-Entwurf konnte nicht gespeichert werden.");
    } finally {
      setBusyAction(null);
    }
  };

  const approveEmail = async (record: ReviewWorkspaceItem) => {
    const outreach = record.latestOutreach;
    if (!outreach) {
      setNotice("E-Mail kann ohne Outreach-ID nicht freigegeben werden.");
      return;
    }

    const draft = drafts[record.id] ?? getDraft(record);
    const strategy = outreach.strategy;
    const hasCallablePhone =
      Boolean(record.lead?.phone) &&
      (strategy === "call_first" ||
        record.lead?.contactStatus === "missing_contact");

    setBusyAction(`${record.id}:email-approval`);
    setNotice(null);
    try {
      await saveReviewDraft({
        id: outreach._id,
        strategy,
        emailBody: draft.emailBody,
        emailSubject: draft.emailSubject,
        followUpDraft: draft.followUpDraft,
        ...(hasCallablePhone ? { phoneScript: draft.phoneScript } : {}),
      });
      await approveEmailDraft({ id: outreach._id });
      setNotice("E-Mail freigegeben.");
    } catch {
      setNotice("E-Mail konnte nicht freigegeben werden.");
    } finally {
      setBusyAction(null);
    }
  };

  return (
    <section className="space-y-4">
      <header className="space-y-2">
        <p className="text-sm text-muted-foreground">Interne Outreach-Prüfung</p>
        <h1 className="text-2xl font-semibold tracking-normal">Review Workspace</h1>
        <p className="max-w-3xl text-sm text-muted-foreground">
          Audits, E-Mail-Empfehlung und Telefonnotizen prüfen, bevor etwas öffentlich
          wird oder eine Freigabe erhält.
        </p>
      </header>

      {notice ? (
        <p className="rounded-md border bg-muted/30 px-3 py-2 text-sm">{notice}</p>
      ) : null}

      <div className="space-y-3">
        {rows.map((record) => {
          const draft = drafts[record.id] ?? getDraft(record);
          const lead = record.lead;
          const audit = record.audit;
          const outreach = record.latestOutreach;
          const strategy = outreach?.strategy;
          const contactSources = [
            lead.email ? `E-Mail: ${lead.email}` : null,
            lead.phone ? `Telefon: ${lead.phone}` : null,
            ...record.sourceSummaries.emailCandidates.map(
              (candidate) =>
                `${candidate.email} · ${candidate.emailSource}${
                  candidate.accepted ? " · akzeptiert" : ""
                }`,
            ),
          ].filter((source): source is string => Boolean(source));
          const skills = record.usedSkills;
          const hasCallablePhone =
            Boolean(lead?.phone) &&
            (strategy === "call_first" ||
              lead?.contactStatus === "missing_contact");
          const publicAuditHref = audit?.slug ? `/audit/${audit.slug}` : null;

          return (
            <Card className="overflow-hidden" key={record.id}>
              <CardHeader className="gap-3 border-b bg-muted/20 p-4">
                <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
                  <div className="min-w-0 space-y-1">
                    <CardTitle className="break-words text-lg">
                      {compactText(lead?.companyName, "Unbenannter Lead")}
                    </CardTitle>
                    <p className="break-all text-sm text-muted-foreground">
                      {compactText(
                        lead?.websiteDomain ?? lead?.websiteUrl,
                        "Keine Domain",
                      )}
                    </p>
                  </div>
                  <div className="flex flex-wrap gap-2">
                    <Badge variant="secondary">{formatStrategy(strategy)}</Badge>
                    <Badge variant="outline">
                      {compactText(lead?.contactStatus, "Kontaktstatus offen")}
                    </Badge>
                    <Badge variant="outline">
                      {compactText(audit?.status, "Auditstatus offen")}
                    </Badge>
                  </div>
                </div>
              </CardHeader>

              <CardContent className="space-y-5 p-4">
                <section className="grid gap-4 lg:grid-cols-[minmax(0,0.8fr)_minmax(0,1.2fr)]">
                  <div className="space-y-3">
                    <h2 className="text-sm font-semibold">Lead-Details</h2>
                    <dl className="grid gap-3 sm:grid-cols-2">
                      <FieldPair label="Nische" value={lead?.niche} />
                      <FieldPair
                        label="Ort"
                        value={[lead?.postalCode, lead?.city].filter(Boolean).join(" ")}
                      />
                      <FieldPair label="Ansprechperson" value={lead?.contactPerson} />
                      <FieldPair label="E-Mail" value={lead?.email} />
                      <FieldPair label="Telefon" value={lead?.phone} />
                      <FieldPair label="Quelle" value={lead?.googleMapsUrl} />
                    </dl>
                    <div className="space-y-1">
                      <h3 className="text-xs font-medium text-muted-foreground">
                        Prioritätsgrund
                      </h3>
                      <p className="break-words text-sm">
                        {compactText(lead?.priorityReason)}
                      </p>
                    </div>
                    <div className="space-y-1">
                      <h3 className="text-xs font-medium text-muted-foreground">
                        Kontaktstrategie
                      </h3>
                      <p className="text-sm">{formatStrategy(strategy)}</p>
                    </div>
                  </div>

                  <div className="space-y-3">
                    <div className="flex flex-wrap items-center justify-between gap-2">
                      <h2 className="text-sm font-semibold">Audit-Zusammenfassung</h2>
                      {publicAuditHref ? (
                        <Button asChild size="sm" type="button" variant="outline">
                          <Link href={publicAuditHref}>
                            <ExternalLink className="size-3.5" />
                            Public-Audit
                          </Link>
                        </Button>
                      ) : (
                        <span className="text-sm text-muted-foreground">
                          Public-Audit ohne Slug
                        </span>
                      )}
                    </div>

                    <label className="block space-y-1">
                      <span className="text-xs font-medium text-muted-foreground">
                        Public-Audit Slug
                      </span>
                      <span className="block break-all text-sm">
                        {compactText(audit?.slug, "Slug offen")}
                      </span>
                    </label>

                    <label className="block space-y-1">
                      <span className="text-xs font-medium text-muted-foreground">
                        Audit Kurzfassung
                      </span>
                      <textarea
                        className={cn(textAreaClassName, "min-h-20")}
                        onChange={(event) =>
                          updateDraft(record.id, "auditSummary", event.target.value)
                        }
                        value={draft.auditSummary}
                      />
                    </label>

                    <label className="block space-y-1">
                      <span className="text-xs font-medium text-muted-foreground">
                        Audit öffentlicher Text
                      </span>
                      <textarea
                        className={cn(textAreaClassName, "min-h-28")}
                        onChange={(event) =>
                          updateDraft(record.id, "auditBody", event.target.value)
                        }
                        value={draft.auditBody}
                      />
                    </label>

                    <div className="flex flex-wrap gap-2">
                      <Button
                        disabled={busyAction === `${record.id}:audit-save`}
                        onClick={() => saveAudit(record)}
                        size="sm"
                        type="button"
                        variant="outline"
                      >
                        <Save className="size-3.5" />
                        Änderungen speichern
                      </Button>
                      <Button
                        disabled={busyAction === `${record.id}:audit-publish`}
                        onClick={() => publishAudit(record)}
                        size="sm"
                        type="button"
                      >
                        Audit veröffentlichen
                      </Button>
                    </div>
                  </div>
                </section>

                <section className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
                  <div className="space-y-3">
                    <h2 className="text-sm font-semibold">Empfohlene E-Mail</h2>
                    <label className="block space-y-1">
                      <span className="text-xs font-medium text-muted-foreground">
                        E-Mail-Betreff
                      </span>
                      <Input
                        aria-label="E-Mail-Betreff"
                        onChange={(event) =>
                          updateDraft(record.id, "emailSubject", event.target.value)
                        }
                        value={draft.emailSubject}
                      />
                    </label>
                    <label className="block space-y-1">
                      <span className="text-xs font-medium text-muted-foreground">
                        E-Mail-Text
                      </span>
                      <textarea
                        aria-label="E-Mail-Text"
                        className={cn(textAreaClassName, "min-h-40")}
                        onChange={(event) =>
                          updateDraft(record.id, "emailBody", event.target.value)
                        }
                        value={draft.emailBody}
                      />
                    </label>
                    <div className="flex flex-wrap gap-2">
                      <Button
                        disabled={busyAction === `${record.id}:outreach-save`}
                        onClick={() => saveOutreach(record)}
                        size="sm"
                        type="button"
                        variant="outline"
                      >
                        <Save className="size-3.5" />
                        Änderungen speichern
                      </Button>
                      <Button
                        disabled={busyAction === `${record.id}:email-approval`}
                        onClick={() => approveEmail(record)}
                        size="sm"
                        type="button"
                      >
                        <MailCheck className="size-3.5" />
                        E-Mail freigeben
                      </Button>
                    </div>
                  </div>

                  <div className="space-y-3">
                    <h2 className="text-sm font-semibold">Telefon & Follow-up</h2>
                    {hasCallablePhone ? (
                      <label className="block space-y-1">
                        <span className="text-xs font-medium text-muted-foreground">
                          Telefon-Skript
                        </span>
                        <textarea
                          className={cn(textAreaClassName, "min-h-32")}
                          onChange={(event) =>
                            updateDraft(record.id, "phoneScript", event.target.value)
                          }
                          value={draft.phoneScript}
                        />
                      </label>
                    ) : (
                      <p className="rounded-md border bg-muted/20 px-3 py-2 text-sm text-muted-foreground">
                        Kein Telefon-Skript erforderlich.
                      </p>
                    )}

                    <label className="block space-y-1">
                      <span className="text-xs font-medium text-muted-foreground">
                        Follow-up-Draft
                      </span>
                      <textarea
                        className={cn(textAreaClassName, "min-h-28")}
                        onChange={(event) =>
                          updateDraft(record.id, "followUpDraft", event.target.value)
                        }
                        value={draft.followUpDraft}
                      />
                    </label>
                  </div>
                </section>

                <section className="space-y-3">
                  <div className="flex flex-wrap gap-2">
                    <DetailToggle
                      isOpen={Boolean(openSources[record.id])}
                      label="Quellen anzeigen"
                      onClick={() =>
                        setOpenSources((current) => ({
                          ...current,
                          [record.id]: !current[record.id],
                        }))
                      }
                    />
                    <DetailToggle
                      isOpen={Boolean(openRaw[record.id])}
                      label="Raw anzeigen"
                      onClick={() =>
                        setOpenRaw((current) => ({
                          ...current,
                          [record.id]: !current[record.id],
                        }))
                      }
                    />
                  </div>

                  {openSources[record.id] ? (
                    <div className="grid gap-3 rounded-md border bg-muted/20 p-3 lg:grid-cols-2">
                      <div className="min-w-0 space-y-2">
                        <h2 className="text-sm font-semibold">Kontaktquellen</h2>
                        {contactSources.length > 0 ? (
                          <ul className="space-y-1 text-sm">
                            {contactSources.map((source, index) => (
                              <li className="break-words" key={`${source}-${index}`}>
                                {source}
                              </li>
                            ))}
                          </ul>
                        ) : (
                          <p className="text-sm text-muted-foreground">
                            Keine Kontaktquellen hinterlegt.
                          </p>
                        )}
                      </div>
                      <div className="min-w-0 space-y-2">
                        <h2 className="text-sm font-semibold">Verwendete Skills</h2>
                        {skills.length > 0 ? (
                          <div className="flex flex-wrap gap-2">
                            {skills.map((skill, index) => (
                              <Badge key={index} variant="outline">
                                {skillLabel(skill)}
                              </Badge>
                            ))}
                          </div>
                        ) : (
                          <p className="text-sm text-muted-foreground">
                            Keine Skills dokumentiert.
                          </p>
                        )}
                      </div>
                    </div>
                  ) : null}

                  {openRaw[record.id] ? (
                    <pre className="max-h-72 overflow-auto rounded-md border bg-muted/20 p-3 text-xs whitespace-pre-wrap">
                      {formatRaw({
                        audit,
                        auditGenerations: record.auditGenerations,
                        latestOutreach: outreach,
                        lead,
                        skillSummaries: record.skillSummaries,
                        sourceSummaries: record.sourceSummaries,
                      })}
                    </pre>
                  ) : null}
                </section>
              </CardContent>
            </Card>
          );
        })}
      </div>
    </section>
  );
}
