import { createFileRoute, Link, Outlet, useRouter, useRouterState } from "@tanstack/react-router";
import { useState } from "react";
import { toast } from "sonner";
import { AppShell, PageHeader } from "@/components/app-shell";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog";
import { Input, NativeSelect, Textarea } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  METHOD_LABEL,
  METHODS,
  RESPONSE_LABEL,
  RESPONSE_TYPES,
  SOLICITATION_STATUS_LABEL,
  type Method,
  type ResponseType,
  type SolicitationStatus,
} from "@/lib/constants";
import { getShellMeta } from "@/lib/server/api-core";
import { listFoundations } from "@/lib/server/api-foundations";
import {
  addSolicitationResponse,
  archiveSolicitation,
  createSolicitation,
  listSolicitations,
} from "@/lib/server/api-pipeline";
import { formatDateTime, moneyRange } from "@/lib/utils";

export const Route = createFileRoute("/outreach")({
  loader: async () => {
    const [meta, solicitations, foundations] = await Promise.all([
      getShellMeta(),
      listSolicitations(),
      listFoundations({ data: {} }),
    ]);
    return { meta, solicitations, foundations };
  },
  component: OutreachPage,
});

function statusVariant(status: string) {
  if (status === "sent" || status === "awarded") return "success" as const;
  if (status === "hold" || status === "queued") return "warning" as const;
  if (status === "declined" || status === "archived") return "destructive" as const;
  return "muted" as const;
}

function OutreachPage() {
  const pathname = useRouterState({ select: (s) => s.location.pathname });
  if (pathname !== "/outreach" && pathname !== "/outreach/") {
    return <Outlet />;
  }
  const { meta, solicitations, foundations } = Route.useLoaderData();
  const router = useRouter();
  const [open, setOpen] = useState(false);
  const [foundationId, setFoundationId] = useState(foundations[0]?.id ?? "");
  const [contact, setContact] = useState("");
  const [role, setRole] = useState("Trustee");
  const [method, setMethod] = useState<Method>("loi");
  const [notes, setNotes] = useState("");
  const [pack, setPack] = useState("");
  const [sendNow, setSendNow] = useState(true);
  const [respFor, setRespFor] = useState<string | null>(null);
  const [respType, setRespType] = useState<ResponseType>("replied");
  const [respNotes, setRespNotes] = useState("");
  const [filter, setFilter] = useState("active");

  const rows = solicitations.filter((s) => {
    if (filter === "active") return s.status !== "archived";
    if (filter === "archived") return s.status === "archived";
    return true;
  });

  async function create(e: React.FormEvent) {
    e.preventDefault();
    try {
      const res = await createSolicitation({
        data: {
          foundationId,
          contact_name: contact,
          contact_role: role,
          method,
          notes,
          package_text: pack || undefined,
          sendNow,
        },
      });
      if (res.held) {
        toast.message("Held — not sent", {
          description: "Determination-letter gate is on. Record queued with who / when / how / what.",
        });
      } else {
        toast.success(res.status === "sent" ? "Solicitation logged as sent" : "Queued");
      }
      setOpen(false);
      await router.invalidate();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not create");
    }
  }

  async function addResp(id: string) {
    try {
      await addSolicitationResponse({
        data: { solicitationId: id, response_type: respType, notes: respNotes },
      });
      toast.success("Response appended");
      setRespFor(null);
      setRespNotes("");
      await router.invalidate();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Failed");
    }
  }

  async function archive(id: string) {
    try {
      await archiveSolicitation({ data: { id } });
      toast.success("Archived");
      await router.invalidate();
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Could not archive");
    }
  }

  return (
    <AppShell hold={meta.hold} unread={meta.unread} noticeCount={meta.noticeCount} inboxUnread={meta.inboxUnread}>
      <PageHeader
        kicker="The sent log · not the catalog search"
        title="What we sent"
        description="This is the only place that shows letters CFL actually prepared or mailed. Catalog search finds listings — it never sends. Open a row to read the exact letter, the original RFP, the date, and any reply."
        actions={
          <Dialog open={open} onOpenChange={setOpen}>
            <DialogTrigger asChild>
              <Button>New solicitation</Button>
            </DialogTrigger>
            <DialogContent
              className="max-w-lg"
              title="Log solicitation"
              description={meta.hold ? "Hold is on — send will queue, not transmit." : "Send writes sent_at and sent_by."}
            >
              <form className="flex flex-col gap-3" onSubmit={create}>
                <div className="flex flex-col gap-1.5">
                  <Label>Foundation</Label>
                  <NativeSelect value={foundationId} onChange={(e) => setFoundationId(e.target.value)}>
                    {foundations.map((f) => (
                      <option key={f.id} value={f.id}>
                        {f.name}
                      </option>
                    ))}
                  </NativeSelect>
                </div>
                <div className="grid gap-3 sm:grid-cols-2">
                  <div className="flex flex-col gap-1.5">
                    <Label>Named contact</Label>
                    <Input required value={contact} onChange={(e) => setContact(e.target.value)} />
                  </div>
                  <div className="flex flex-col gap-1.5">
                    <Label>Role</Label>
                    <Input value={role} onChange={(e) => setRole(e.target.value)} />
                  </div>
                </div>
                <div className="flex flex-col gap-1.5">
                  <Label>How</Label>
                  <NativeSelect value={method} onChange={(e) => setMethod(e.target.value as Method)}>
                    {METHODS.map((m) => (
                      <option key={m} value={m}>
                        {METHOD_LABEL[m]}
                      </option>
                    ))}
                  </NativeSelect>
                </div>
                <div className="flex flex-col gap-1.5">
                  <Label>What was sent (letter snapshot)</Label>
                  <Textarea
                    value={pack}
                    onChange={(e) => setPack(e.target.value)}
                    placeholder="Paste the exact letter. This is the record of what the grant reads like."
                  />
                </div>
                <div className="flex flex-col gap-1.5">
                  <Label>Notes</Label>
                  <Input value={notes} onChange={(e) => setNotes(e.target.value)} />
                </div>
                <label className="flex items-center gap-2 text-sm">
                  <input type="checkbox" checked={sendNow} onChange={(e) => setSendNow(e.target.checked)} />
                  Mark as sent now
                </label>
                <Button type="submit">Save record</Button>
              </form>
            </DialogContent>
          </Dialog>
        }
      />

      {meta.hold ? (
        <div className="mb-6 rounded-xl border border-warning/30 bg-warning/8 px-4 py-3 text-sm">
          <span className="font-medium text-warning">Sending hold is on.</span>{" "}
          <span className="text-muted-foreground">
            New requests are logged here but not mailed until a staff member sends them. Rows marked
            Sent are the historical record of what went out. Sample drafts stay On hold.
          </span>
        </div>
      ) : null}

      <Card className="mb-6">
        <CardContent className="p-5">
          <p className="text-[11px] font-medium tracking-[0.16em] text-muted-foreground uppercase">How to read this list</p>
          <div className="mt-3 grid gap-3 sm:grid-cols-3">
            <p className="text-sm leading-relaxed text-muted-foreground">
              <span className="font-medium text-foreground">Date sent</span> is when the letter went out. “Not sent” means
              the package is ready and sitting on hold — it was never mailed.
            </p>
            <p className="text-sm leading-relaxed text-muted-foreground">
              <span className="font-medium text-foreground">View detail</span> opens the exact letter we sent, the original
              request for proposal it answered, and every reply, in order.
            </p>
            <p className="text-sm leading-relaxed text-muted-foreground">
              <span className="font-medium text-foreground">On hold / Queued</span> is not a submission. Nothing leaves
              CFL until a staff member sends it after the hold is lifted.
            </p>
          </div>
        </CardContent>
      </Card>

      <div className="mb-4 flex flex-wrap gap-2">
        {(
          [
            ["active", "Active"],
            ["all", "All"],
            ["archived", "Archived"],
          ] as const
        ).map(([id, label]) => (
          <button
            key={id}
            type="button"
            onClick={() => setFilter(id)}
            className={`h-9 rounded-full px-3 text-sm ${
              filter === id ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"
            }`}
          >
            {label}
          </button>
        ))}
      </div>

      <div className="overflow-hidden rounded-xl bg-card shadow-[var(--shadow-border)]">
        <div className="overflow-x-auto">
        <table className="w-full min-w-[860px] text-left text-sm">
          <thead>
            <tr className="bg-primary text-primary-foreground">
              <th className="px-4 py-3 font-semibold">
                Grantor
                <span className="mt-0.5 block text-xs font-normal text-primary-foreground/75">Who we asked.</span>
              </th>
              <th className="px-4 py-3 font-semibold">
                Contact
                <span className="mt-0.5 block text-xs font-normal text-primary-foreground/75">Named person at the foundation.</span>
              </th>
              <th className="px-4 py-3 font-semibold">
                Amount
                <span className="mt-0.5 block text-xs font-normal text-primary-foreground/75">What we asked for.</span>
              </th>
              <th className="px-4 py-3 font-semibold">
                Date sent
                <span className="mt-0.5 block text-xs font-normal text-primary-foreground/75">When it went out. Blank = not mailed.</span>
              </th>
              <th className="px-4 py-3 font-semibold">
                Response
                <span className="mt-0.5 block text-xs font-normal text-primary-foreground/75">Latest reply from the grantor.</span>
              </th>
              <th className="px-4 py-3 font-semibold">
                Actions
                <span className="mt-0.5 block text-xs font-normal text-primary-foreground/75">Open the letter and RFP.</span>
              </th>
            </tr>
          </thead>
          <tbody>
            {rows.map((s) => (
              <tr key={s.id} className="border-b border-border last:border-0">
                <td className="px-4 py-4 align-top">
                  <p className="font-medium">{s.foundation_name ?? "Unnamed foundation"}</p>
                  <div className="mt-1 flex flex-wrap items-center gap-1.5">
                    <Badge variant={statusVariant(s.status)}>
                      {SOLICITATION_STATUS_LABEL[s.status as SolicitationStatus] ?? s.status}
                    </Badge>
                    <Badge variant="outline">{METHOD_LABEL[s.method as Method] ?? s.method}</Badge>
                  </div>
                  {s.opportunity_title ? (
                    <p className="mt-1 max-w-xs truncate text-xs text-muted-foreground">{s.opportunity_title}</p>
                  ) : null}
                </td>
                <td className="px-4 py-4 align-top">
                  <p>{s.contact_name}</p>
                  <p className="text-xs text-muted-foreground">{s.contact_role ?? "—"}</p>
                </td>
                <td className="px-4 py-4 align-top tabular text-success">
                  {moneyRange(s.amount_min ?? null, s.amount_max ?? null)}
                </td>
                <td className="px-4 py-4 align-top">
                  <p>{s.sent_at ? formatDateTime(s.sent_at) : "Not sent"}</p>
                  {s.sent_by ? <p className="text-xs text-muted-foreground">{s.sent_by}</p> : null}
                </td>
                <td className="px-4 py-4 align-top text-muted-foreground">
                  {s.latest_response
                    ? (RESPONSE_LABEL[s.latest_response as ResponseType] ?? s.latest_response)
                    : "—"}
                </td>
                <td className="px-4 py-4 align-top">
                  <div className="flex flex-wrap gap-2">
                    <Button size="sm" asChild>
                      <Link to="/outreach/$id" params={{ id: s.id }}>
                        View detail
                      </Link>
                    </Button>
                    {s.status !== "archived" ? (
                      <Button size="sm" variant="archive" onClick={() => archive(s.id)}>
                        Archive
                      </Button>
                    ) : null}
                  </div>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
        </div>
      </div>

      <Dialog open={Boolean(respFor)} onOpenChange={(v) => !v && setRespFor(null)}>
        <DialogContent title="Append response" description="Prior responses are never overwritten or deleted.">
          <div className="flex flex-col gap-3">
            <NativeSelect value={respType} onChange={(e) => setRespType(e.target.value as ResponseType)}>
              {RESPONSE_TYPES.map((t) => (
                <option key={t} value={t}>
                  {RESPONSE_LABEL[t]}
                </option>
              ))}
            </NativeSelect>
            <Textarea value={respNotes} onChange={(e) => setRespNotes(e.target.value)} placeholder="Notes" />
            <Button onClick={() => respFor && addResp(respFor)}>Append</Button>
          </div>
        </DialogContent>
      </Dialog>
    </AppShell>
  );
}
