import { createFileRoute, Link, useRouter } from "@tanstack/react-router";
import { useState } from "react";
import { toast } from "sonner";
import { AppShell, PageHeader } from "@/components/app-shell";
import { FitScore } from "@/components/fit-score";
import { PriorityBadge } from "@/components/priority-badge";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Dialog, DialogContent } from "@/components/ui/dialog";
import { getShellMeta } from "@/lib/server/api-core";
import { scoreOpportunityWithGrok } from "@/lib/server/api-ai";
import { generateDraft } from "@/lib/server/api-drafts";
import { getOpportunity } from "@/lib/server/api-opps";
import { formatDate, money, relativeDeadline } from "@/lib/utils";

export const Route = createFileRoute("/opportunities/$id")({
  loader: async ({ params }) => {
    const [meta, detail] = await Promise.all([getShellMeta(), getOpportunity({ data: { id: params.id } })]);
    return { meta, detail };
  },
  component: OpportunityDetail,
});

function OpportunityDetail() {
  const { meta, detail } = Route.useLoaderData();
  const { opp, events, drafts } = detail;
  const router = useRouter();
  const [open, setOpen] = useState(false);
  const [busy, setBusy] = useState(false);
  const [scoring, setScoring] = useState(false);

  if (!opp) {
    return (
      <AppShell hold={meta.hold} unread={meta.unread} noticeCount={meta.noticeCount} inboxUnread={meta.inboxUnread}>
        <p>Opportunity not found.</p>
      </AppShell>
    );
  }

  const current = opp;

  async function generate(kind: "narrative" | "loi") {
    setBusy(true);
    try {
      const res = await generateDraft({
        data: { opportunityId: current.id, matchId: current.match_id ?? undefined, kind },
      });
      toast.message(res.flags.length ? "Draft generated with flags" : "Draft generated", {
        description: res.flags.length ? "Validation blocked prohibited constructions." : "Ready for human review.",
      });
      setOpen(false);
      await router.navigate({ to: "/review/$id", params: { id: res.id } });
    } catch (err) {
      toast.error(err instanceof Error ? err.message : "Draft failed");
    } finally {
      setBusy(false);
    }
  }

  return (
    <AppShell hold={meta.hold} unread={meta.unread} noticeCount={meta.noticeCount} inboxUnread={meta.inboxUnread}>
      <PageHeader
        kicker={opp.source}
        title={opp.title}
        description={opp.funder_name}
        actions={
          <>
            {opp.url ? (
              <Button variant="outline" asChild>
                <a href={opp.url} target="_blank" rel="noreferrer">
                  Source
                </a>
              </Button>
            ) : null}
            <Button
              variant="outline"
              disabled={scoring}
              onClick={async () => {
                setScoring(true);
                try {
                  const res = await scoreOpportunityWithGrok({ data: { opportunityId: opp.id, force: true } });
                  toast.success(
                    res.cached ? "Using stored Grok brief" : `Grok: ${"priority" in res ? res.priority : "scored"}`,
                  );
                  await router.invalidate();
                } catch (err) {
                  toast.error(err instanceof Error ? err.message : "Score failed");
                } finally {
                  setScoring(false);
                }
              }}
            >
              {scoring ? "Asking Grok…" : "Ask Grok: go after this?"}
            </Button>
            <Button onClick={() => setOpen(true)} disabled={Boolean(opp.knockout_reason)}>
              Generate draft
            </Button>
          </>
        }
      />

      <Dialog open={open} onOpenChange={setOpen}>
        <DialogContent title="Generate draft" description="Assistive only. A human reviews and sends. No auto-submission.">
          <div className="flex flex-col gap-2">
            <Button disabled={busy} onClick={() => generate("loi")}>
              Letter of inquiry
            </Button>
            <Button variant="outline" disabled={busy} onClick={() => generate("narrative")}>
              Multi-section narrative
            </Button>
          </div>
        </DialogContent>
      </Dialog>

      <div className="grid gap-4 lg:grid-cols-[1.2fr_0.8fr]">
        <div className="flex flex-col gap-4">
          <Card>
            <CardContent className="p-5">
              <div className="flex items-end justify-between gap-4">
                <div>
                  <p className="text-[11px] tracking-[0.16em] text-muted-foreground uppercase">Fit</p>
                  <FitScore score={opp.fit_score} knockout={opp.knockout_reason} size="lg" />
                </div>
                <Badge variant={opp.status === "open" ? "success" : "muted"}>{opp.status}</Badge>
              </div>
              <p className="mt-4 text-sm">
                {opp.knockout_reason ?? opp.fit_reason ?? "Not yet scored."}
              </p>
            </CardContent>
          </Card>
          <Card>
            <CardContent className="p-5">
              <div className="mb-3 flex items-center justify-between gap-3">
                <p className="text-[11px] tracking-[0.16em] text-muted-foreground uppercase">Grok · go after?</p>
                <PriorityBadge priority={opp.ai_priority} importance={opp.ai_importance} />
              </div>
              {opp.ai_rationale ? (
                <>
                  <p className="text-sm leading-relaxed">{opp.ai_rationale}</p>
                  <p className="mt-2 text-xs text-muted-foreground">
                    Effort {opp.ai_effort ?? "—"}
                    {opp.ai_model ? ` · ${opp.ai_model}` : ""}
                  </p>
                  {opp.ai_overlap && opp.ai_overlap.length > 0 ? (
                    <ul className="mt-3 flex flex-wrap gap-1.5">
                      {opp.ai_overlap.map((k) => (
                        <li key={k} className="rounded-full bg-muted px-2 py-0.5 text-[11px] text-muted-foreground">
                          {k}
                        </li>
                      ))}
                    </ul>
                  ) : null}
                  {opp.ai_risks && opp.ai_risks.length > 0 ? (
                    <ul className="mt-3 list-disc space-y-1 pl-4 text-xs text-muted-foreground">
                      {opp.ai_risks.map((k) => (
                        <li key={k}>{k}</li>
                      ))}
                    </ul>
                  ) : null}
                </>
              ) : (
                <p className="text-sm text-muted-foreground">
                  Keyword fit is automatic. Ask Grok whether this is important enough to spend staff time on.
                </p>
              )}
            </CardContent>
          </Card>
          <Card>
            <CardContent className="p-5">
              <p className="mb-2 text-[11px] tracking-[0.16em] text-muted-foreground uppercase">
                Amount, deadline & eligibility
              </p>
              <dl className="grid grid-cols-2 gap-4 text-sm">
                <div>
                  <dt className="text-muted-foreground">Amount</dt>
                  <dd className="tabular">
                    {opp.amount_min || opp.amount_max
                      ? `${money(opp.amount_min)} – ${money(opp.amount_max)}`
                      : "Not stated"}
                  </dd>
                </div>
                <div>
                  <dt className="text-muted-foreground">Deadline</dt>
                  <dd>
                    {formatDate(opp.deadline)}{" "}
                    <span className="text-muted-foreground">({relativeDeadline(opp.deadline)})</span>
                  </dd>
                </div>
              </dl>
              <p className="mt-4 text-sm leading-relaxed">{opp.eligibility_raw || "Eligibility not captured."}</p>
            </CardContent>
          </Card>
        </div>
        <div className="flex flex-col gap-4">
          <Card>
            <CardContent className="p-5">
              <p className="mb-3 text-[11px] tracking-[0.16em] text-muted-foreground uppercase">Drafts</p>
              {drafts.length === 0 ? (
                <p className="text-sm text-muted-foreground">None yet. Generate a draft to open the review queue.</p>
              ) : (
                <ul className="space-y-2">
                  {drafts.map((d) => (
                    <li key={d.id}>
                      <Link to="/review/$id" params={{ id: d.id }} className="text-sm font-medium hover:text-primary">
                        {d.title}
                      </Link>
                      <p className="text-xs text-muted-foreground">{d.status}</p>
                    </li>
                  ))}
                </ul>
              )}
            </CardContent>
          </Card>
          <Card>
            <CardContent className="p-5">
              <p className="mb-3 text-[11px] tracking-[0.16em] text-muted-foreground uppercase">Audit</p>
              {events.length === 0 ? (
                <p className="text-sm text-muted-foreground">Scoring stored on match create.</p>
              ) : (
                <ul className="space-y-2 text-sm">
                  {events.map((e) => (
                    <li key={e.id}>
                      <span className="text-muted-foreground">{formatDate(e.created_at)}</span> · {e.event_type}
                      {e.notes ? <p className="text-muted-foreground">{e.notes}</p> : null}
                    </li>
                  ))}
                </ul>
              )}
            </CardContent>
          </Card>
        </div>
      </div>
    </AppShell>
  );
}
