import { useState, type ReactNode } from "react";
import { clinicianApi } from "../../api/client";
import type { CheckRun, PatientDetail } from "../../api/types";
import { doseLabels, formatDate, medicinePlan, patientProfile } from "../../flow";
import { byTier, checkHeadline, latestMarks } from "../../logic/checks";
import { calculatedEgfrLine, doseExtras, findingWording, kidneyLimitLine, notCheckedFor, resultExtras, testMedicines } from "../../logic/engine-extras";
import { factDetail, firstName, listNames, pronouns, whenLabel } from "../../logic/format";
import { urgentGate } from "../../logic/urgent";
import { zoneOffset } from "../../logic/windows";
import { FindingsMix } from "../charts";
import { confirmCall, useCallConfirmation } from "../checkin/confirmations";
import { buttonVariants, Card, cn, Icon, type IconName, Notice, SectionHeader, Segmented, StatusPill, type Tone } from "../kit";
import { tabPath } from "../patient/links";
import { SourceDrawer, type SourceRef } from "../patient/SourceDrawer";
import { Link } from "../router";
import { useClinician } from "../session";
import { FindingCard } from "./FindingCard";

type View = "findings" | "know" | "medicines" | "monitoring";
const views: Record<View, string> = { findings: "Findings", know: "What we know", medicines: "Medicine by medicine", monitoring: "Monitoring" };
const doseLook: Record<string, { tone: Tone; icon: IconName }> = {
  within_usual_range: { tone: "green", icon: "checkbox-circle-fill" },
  above_limit: { tone: "red", icon: "error-warning-fill" },
  check_with_pharmacist: { tone: "amber", icon: "question-fill" },
  not_enough_info: { tone: "grey", icon: "information-fill" },
};
const rows = "m-0 flex list-none flex-col p-0";
const row = "flex flex-col gap-1.5 py-3 shadow-[inset_0_-1px_0_var(--color-hairline)] last:shadow-none";
const meta = "text-[12.5px] leading-[18px] text-muted";
const sourceLink =
  "inline-flex cursor-pointer items-center gap-1.5 self-start rounded-md border-0 bg-transparent p-0 font-mono text-[12px] text-muted underline decoration-line underline-offset-4 outline-none hover:text-ink focus-visible:shadow-[0_0_0_2px_var(--color-brand)]";

const Panel = ({ title, children, className }: { title: string; children: ReactNode; className?: string }) => (
  <section aria-label={title}>
    <Card as="div" className={cn("flex flex-col gap-2", className)}>
      <SectionHeader title={title} />
      {children}
    </Card>
  </section>
);

/** YCI-1a: an Urgent review finding leads with a call; Ask Yasmar waits for "I will speak to Mariam today". */
export function UrgentBanner({ patient, findings }: { patient: PatientDetail; findings: { id: string; tier: string }[] }) {
  const { clinic } = useClinician();
  const confirmation = useCallConfirmation(patient.id);
  const gate = urgentGate({ findings, patientId: patient.id, patientName: patient.name, confirmation, now: new Date(), clinicOffset: zoneOffset(clinic.timeZone) });
  if (gate.mode === "none") return null;
  const first = firstName(patient.name);
  return (
    <Notice
      tone="urgent"
      role="alert"
      icon="alarm-warning-fill"
      title={`Urgent review: call ${first} before ${pronouns(patient.pronoun).possessive} next dose.`}
      actions={
        <>
          {patient.phone ? (
            <a className={cn(buttonVariants({ variant: "red" }), "no-underline")} href={`tel:${patient.phone.replace(/[^\d+]/g, "")}`}>
              <Icon name="phone-fill" /> {gate.callLine} · {patient.phone}
            </a>
          ) : (
            <span className="text-[13px] text-red-text">No phone number is shared. Use the number in your own records.</span>
          )}
          {gate.canAskYasmar ? (
            <StatusPill tone="green" icon="checkbox-circle-fill">
              You will speak to {first} today
            </StatusPill>
          ) : (
            <button type="button" className={cn(buttonVariants(), "bg-page text-red-text hover:bg-white/70")} onClick={() => confirmCall(patient.id)}>
              {gate.confirmLine}
            </button>
          )}
        </>
      }
    >
      <p className="m-0">
        Yasmar can follow up only after you confirm you will speak to {pronouns(patient.pronoun).object} today. Yasmar is never the only answer to something urgent.
      </p>
    </Notice>
  );
}

export function FindingsView({ patient, check, onCheck }: { patient: PatientDetail; check: CheckRun; onCheck: (c: CheckRun) => void }) {
  const { clinic } = useClinician();
  const [view, setView] = useState<View>("findings");
  const [source, setSource] = useState<SourceRef | null>(null);
  const confirmation = useCallConfirmation(patient.id);
  const a = check.assessment;
  const head = checkHeadline(a, patient.name);
  const first = firstName(patient.name);
  const marks = latestMarks(check);
  const gate = urgentGate({ findings: a.contextual.findings, patientId: patient.id, patientName: patient.name, confirmation, now: new Date(), clinicOffset: zoneOffset(clinic.timeZone) });
  const profile = patientProfile(a);
  // The same medicine read from two records shows once (it is one medicine in the check).
  const plan = medicinePlan(a).filter((m, i, all) => all.findIndex((o) => o.fact.label === m.fact.label && o.fact.detail === m.fact.detail) === i);
  const calculated = calculatedEgfrLine(resultExtras(a.contextual).calculated_egfr);
  const doseFor = (id: string, name: string) =>
    a.contextual.dose_check.find((d) => d.medicine_id === id) ?? a.contextual.dose_check.find((d) => d.medicine.toLowerCase() === name.toLowerCase());
  return (
    <div className="flex flex-col gap-4">
      {patient.newInformation && (
        <Notice
          role="status"
          icon="sparkling-line"
          title="New information since your last check"
          actions={
            <Link className={buttonVariants({ variant: "primary", size: "sm", className: "no-underline" })} to={tabPath(patient.id, "records")}>
              See the records
            </Link>
          }
        >
          <p className="m-0">{listNames(patient.newInformation.items)}. Past results never change; a new run is kept beside this one.</p>
        </Notice>
      )}
      {check.withheldSome && (
        <Notice tone="amber" icon="information-line">
          Not everything was shared. {first} held back some medicines or conditions, so this check may be incomplete.
        </Notice>
      )}
      <UrgentBanner patient={patient} findings={a.contextual.findings} />
      <section aria-label="Result">
        <Card as="div" className="flex flex-col gap-4">
          <SectionHeader
            title="Result"
            action={
              <span className="text-right font-mono text-[12px] text-subtle">
                Ran {whenLabel(check.ranAt)} · {check.ranBy}
              </span>
            }
          />
          <p className="m-0 text-[15px] leading-[22px] font-medium text-ink">{head.headline}</p>
          <div className="grid grid-cols-2 gap-3">
            <div className="flex flex-col gap-1 rounded-xl bg-tile px-4 py-3">
              <small className="text-[12.5px] text-muted">The list alone</small>
              <span className="flex flex-wrap items-baseline gap-x-1.5">
                <b className="text-[28px] leading-8 font-semibold tracking-[-0.02em] text-ink tabular-nums">{head.before}</b>
                <span className="text-[13px] font-medium text-subtle">{head.before === 1 ? "finding" : "findings"}</span>
              </span>
            </div>
            <div className="flex flex-col gap-1 rounded-xl bg-page px-4 py-3 shadow-[inset_0_0_0_1px_var(--color-line)]">
              <small className="text-[12.5px] text-muted">With {first}'s details</small>
              <span className="flex flex-wrap items-baseline gap-x-1.5">
                <b className="text-[28px] leading-8 font-semibold tracking-[-0.02em] text-ink tabular-nums">{head.after}</b>
                <span className="text-[13px] font-medium text-subtle">{head.after === 1 ? "finding to review" : "findings to review"}</span>
              </span>
            </div>
          </div>
          <FindingsMix findings={a.contextual.findings} />
          <p className={cn("m-0", meta)}>Each finding links to the record lines it came from. A clinician decides what happens next.</p>
        </Card>
      </section>
      <div className="-mx-1 overflow-x-auto px-1 py-0.5">
        <Segmented label="Result views" options={(Object.keys(views) as View[]).map((v) => ({ value: v, label: views[v] }))} value={view} onChange={setView} />
      </div>
      {view === "findings" && (
        <section className="flex flex-col gap-3" aria-label="Findings">
          {byTier(a.contextual.findings).map((f) => (
            <FindingCard key={f.id} finding={f} check={check} patient={patient} mark={marks.get(f.id)} canAskYasmar={gate.canAskYasmar} onSource={setSource} onMarked={(m) => onCheck({ ...check, marks: [...check.marks, m] })} />
          ))}
          {!a.contextual.findings.length && <p className="m-0 rounded-2xl bg-tile px-5 py-6 text-center text-[14px] font-medium text-ink">No findings. This does not mean the prescription is safe.</p>}
        </section>
      )}
      {view === "know" && (
        <Panel title={`What we know about ${first}`}>
          <ul className={rows}>
            {profile.map((item) => (
              <li key={item.id} className={row}>
                <div className="flex flex-wrap items-center justify-between gap-2">
                  <span className="flex min-w-0 flex-col">
                    <span className="text-[12.5px] text-muted">{item.label}</span>
                    <span className="text-[14px] leading-5 font-medium text-ink">{item.value ?? "Not recorded"}</span>
                  </span>
                  <StatusPill
                    size="sm"
                    tone={item.status === "used" ? "green" : item.status === "missing" ? "amber" : "grey"}
                    icon={item.status === "used" ? "checkbox-circle-fill" : item.status === "missing" ? "error-warning-fill" : "information-fill"}
                  >
                    {item.status === "used" ? "Used by a rule" : item.status === "missing" ? "Missing" : "Not read by any current rule"}
                  </StatusPill>
                </div>
                <small className={meta}>{item.note}</small>
                {item.fact && (
                  <button type="button" className={sourceLink} onClick={() => setSource({ recordId: item.fact!.sourceId, title: check.recordTitles[item.fact!.sourceId] ?? "Record", lines: [item.fact!.line] })}>
                    <Icon name="file-text-line" size={14} />
                    {check.recordTitles[item.fact.sourceId] ?? "Record"} · line {item.fact.line}
                  </button>
                )}
              </li>
            ))}
            {calculated && (
              <li className={row}>
                <div className="flex flex-wrap items-center justify-between gap-2">
                  <span className="flex min-w-0 flex-col">
                    <span className="text-[12.5px] text-muted">Kidney function (calculated)</span>
                    <span className="text-[14px] leading-5 font-medium text-ink">{calculated}</span>
                  </span>
                  <StatusPill size="sm" tone="amber" icon="error-warning-fill">
                    Calculated, not measured
                  </StatusPill>
                </div>
              </li>
            )}
          </ul>
        </Panel>
      )}
      {view === "medicines" && (
        <Panel title="Medicine by medicine">
          <ul className={rows}>
            {plan.map((m) => {
              const limit = doseExtras(doseFor(m.fact.id, m.fact.label) ?? ({} as never)).kidney_limit;
              const line = kidneyLimitLine(limit);
              const label = limit && m.status === "within_usual_range" ? "Within the kidney-adjusted limit" : limit && m.status === "above_limit" ? "Above the kidney-adjusted limit" : doseLabels[m.status];
              const look = doseLook[m.status] ?? doseLook.not_enough_info;
              return (
                <li key={m.fact.id} className={row}>
                  <div className="flex flex-wrap items-start justify-between gap-2">
                    <span className="flex min-w-0 flex-col gap-0.5">
                      <span className="flex flex-wrap items-center gap-2">
                        <b className="text-[14px] leading-5 font-medium text-ink">{m.fact.label}</b>
                        {check.newMedicineIds.includes(m.fact.id) && (
                          <StatusPill tone="blue" size="sm" icon="sparkling-line">
                            New
                          </StatusPill>
                        )}
                      </span>
                      <small className={meta}>{factDetail(m.fact.detail)}</small>
                    </span>
                    <StatusPill size="sm" tone={look.tone} icon={look.icon}>
                      {label}
                    </StatusPill>
                  </div>
                  {line && <small className="text-[12.5px] leading-[18px] text-body">Kidney-adjusted limit: {line}</small>}
                  <small className={meta}>{m.findings.length ? `In ${m.findings.length === 1 ? "1 finding" : `${m.findings.length} findings`}: ${m.findings.map((f) => findingWording(f, check.details[f.id]).title).join("; ")}` : "No finding names it"}</small>
                </li>
              );
            })}
          </ul>
        </Panel>
      )}
      {view === "monitoring" && (
        <Panel title="Monitoring">
          <ul className={rows}>
            {check.monitoring.map((t) => {
              const engineTest = a.contextual.tests_to_ask_about.find((x) => x.test === t.test);
              const names = engineTest ? testMedicines(engineTest, t.medicines) : t.medicines;
              return (
                <li key={t.test} className={cn(row, "sm:flex-row sm:items-center sm:justify-between")}>
                  <span className="flex min-w-0 flex-col gap-0.5">
                    <b className="text-[14px] leading-5 font-medium text-ink">{t.test}</b>
                    <small className={meta}>{names.length ? `Needed with ${listNames(names)}` : t.test === "Weight" ? "Needed for dose limits under 50 kg" : "Needed with the medicines on this list"}</small>
                  </span>
                  <StatusPill size="sm" tone={t.onFile ? "green" : "amber"} icon={t.onFile ? "calendar-check-fill" : "error-warning-fill"} className="self-start sm:self-auto">
                    {t.onFile ? `On file · ${formatDate(t.onFile)}` : "Not recorded"}
                  </StatusPill>
                </li>
              );
            })}
          </ul>
        </Panel>
      )}
      <Panel title="Not checked" className="bg-tile shadow-none">
        <ul className="m-0 flex flex-col gap-1.5 pl-5 text-[13px] leading-[19px] text-body">
          {notCheckedFor(check).map((l) => (
            <li key={l}>{l}</li>
          ))}
        </ul>
        <p className={cn("m-0 pt-1", meta)}>
          Engine <span className="font-mono">{check.versions.engine}</span> · rules <span className="font-mono">{check.versions.rules}</span>
          {check.versions.rulesReviewed ? " (reviewed)" : " (not yet reviewed)"}
        </p>
        <div className="flex flex-wrap gap-2 pt-2">
          {/* The backend sends a printable page for format=pdf; the browser's Print saves it as a PDF. */}
          <a className={buttonVariants({ variant: "outline", className: "no-underline" })} href={clinicianApi.exportUrl(check.id, "pdf")} target="_blank" rel="noreferrer">
            <Icon name="download-2-line" /> Printable evidence (save as PDF)
          </a>
          <a className={buttonVariants({ variant: "outline", className: "no-underline" })} href={clinicianApi.exportUrl(check.id, "json")} download>
            <Icon name="download-2-line" /> JSON
          </a>
        </div>
      </Panel>
      <SourceDrawer source={source} onClose={() => setSource(null)} />
    </div>
  );
}
