"use client";

import { useEffect, useId, useMemo, useState } from "react";
import type {
  FieldConfig,
  FieldHistoryEntry,
  FormConfig,
  ReportPayload,
  SelectOption,
  StageSectionConfig,
} from "@/types/form";
import { STAGE_OPTION_GROUP_ID } from "@/config/form";
import { StageIcon } from "./StageIcon";

interface ReportViewProps {
  config: FormConfig;
  cid: string;
  cs: string;
}

type LoadState =
  | { kind: "loading" }
  | { kind: "error"; message: string }
  | { kind: "ready"; data: ReportPayload };

type PathwayState = "past" | "current" | "future";

const STAGE_RANK: Record<string, number> = {
  Inquiry: 0,
  Organizing: 1,
  Feasibility: 2,
  "Business feasibility": 3,
  "Store Implementation": 4,
  "Stabilize newly opened co-op": 5,
};

export function ReportView({ config, cid, cs }: ReportViewProps) {
  const [load, setLoad] = useState<LoadState>({ kind: "loading" });

  useEffect(() => {
    let cancelled = false;
    async function go() {
      try {
        const url = new URL("/api/report", window.location.origin);
        url.searchParams.set("cid", cid);
        url.searchParams.set("cs", cs);
        const res = await fetch(url.toString(), { cache: "no-store" });
        if (!res.ok) {
          const text = await res.text();
          let message = `Could not load report (HTTP ${res.status}).`;
          try {
            const j = JSON.parse(text) as { error?: string };
            if (j.error) message = j.error;
          } catch { /* default */ }
          if (!cancelled) setLoad({ kind: "error", message });
          return;
        }
        const data: ReportPayload = await res.json();
        if (!cancelled) setLoad({ kind: "ready", data });
      } catch (e) {
        if (!cancelled) {
          setLoad({
            kind: "error",
            message: e instanceof Error ? e.message : "Unexpected error loading report.",
          });
        }
      }
    }
    void go();
    return () => {
      cancelled = true;
    };
  }, [cid, cs]);

  const sectionsToRender = useMemo(() => {
    if (load.kind !== "ready") return [];
    const { currentStage, fieldHistory } = load.data;
    const currentRank = STAGE_RANK[currentStage] ?? 0;
    return config.sections
      .map((section) => {
        const fieldsWithHistory = section.fields.filter(
          (f) => fieldHistory[f.name] && fieldHistory[f.name].length > 0,
        );
        const pathwayState: PathwayState =
          section.rank < currentRank ? "past" : section.rank === currentRank ? "current" : "future";
        return { section, fieldsWithHistory, pathwayState };
      })
      .filter((e) => e.fieldsWithHistory.length > 0);
  }, [load, config.sections]);

  if (load.kind === "loading") return <LoadingState />;
  if (load.kind === "error") return <ErrorState message={load.message} />;

  const { data } = load;
  const stageOpts = data.options?.[STAGE_OPTION_GROUP_ID] ?? [];
  const currentStageLabel =
    stageOpts.find((o) => o.value === data.currentStage)?.label ?? data.currentStage;
  const currentRank = STAGE_RANK[data.currentStage] ?? 0;

  const dateRange = computeDateRange(data.activities.map((a) => a.date));
  const totalActivities = data.activities.length;
  const totalFieldsTracked = Object.keys(data.fieldHistory).length;

  return (
    <div className="space-y-5">
      <ReportContextHeader
        orgName={data.orgName}
        currentStageLabel={currentStageLabel}
        currentRank={currentRank}
        totalActivities={totalActivities}
        totalFieldsTracked={totalFieldsTracked}
        dateRange={dateRange}
      />

      {sectionsToRender.length === 0 ? (
        <EmptyState />
      ) : (
        <ol className="relative space-y-5 md:pl-12">
          {sectionsToRender.map((entry, i) => {
            const { section, pathwayState, fieldsWithHistory } = entry;
            const nextState =
              i < sectionsToRender.length - 1 ? sectionsToRender[i + 1].pathwayState : undefined;
            return (
              <li key={section.id} className="relative list-none">
                <MobileStem show={i > 0} state={pathwayState} />
                <RailMarker rank={section.rank} state={pathwayState} nextState={nextState} />
                <ReportSection
                  section={section}
                  fields={fieldsWithHistory}
                  history={data.fieldHistory}
                  options={data.options ?? {}}
                  isCurrent={pathwayState === "current"}
                  defaultOpen={pathwayState === "current" || section.rank === 0}
                />
              </li>
            );
          })}
        </ol>
      )}
    </div>
  );
}

function ReportContextHeader({
  orgName,
  currentStageLabel,
  currentRank,
  totalActivities,
  totalFieldsTracked,
  dateRange,
}: {
  orgName: string;
  currentStageLabel: string;
  currentRank: number;
  totalActivities: number;
  totalFieldsTracked: number;
  dateRange: { from: string; to: string } | null;
}) {
  return (
    <header className="rounded-lg border border-rule bg-paper-2/40 px-6 py-5 sm:px-7 sm:py-6">
      <p className="text-[11px] uppercase tracking-[0.18em] text-ink-mute">Report for</p>
      <h1 className="mt-1 font-display text-3xl font-medium leading-tight tracking-tight text-ink sm:text-[34px]">
        {orgName}
      </h1>
      <div className="mt-4 flex items-center gap-3">
        <StageProgress currentRank={currentRank} />
        <span className="text-[10px] uppercase tracking-[0.16em] font-medium text-ink-mute">
          Current stage
        </span>
      </div>
      <p className="mt-1.5 font-display text-xl sm:text-2xl font-medium leading-tight tracking-tight text-leaf-800">
        {currentStageLabel || "—"}
      </p>
      <dl className="mt-5 grid grid-cols-3 gap-3 border-t border-rule-soft pt-4 text-sm sm:gap-6">
        <Stat label="Check-ins" value={String(totalActivities)} />
        <Stat label="Fields tracked" value={String(totalFieldsTracked)} />
        <Stat
          label="Span"
          value={dateRange ? `${formatShortDate(dateRange.from)} - ${formatShortDate(dateRange.to)}` : "—"}
        />
      </dl>
    </header>
  );
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <dt className="text-[10px] uppercase tracking-[0.14em] font-medium text-ink-mute">
        {label}
      </dt>
      <dd className="mt-0.5 font-display text-base font-medium text-ink tabular-nums sm:text-lg">
        {value}
      </dd>
    </div>
  );
}

function StageProgress({ currentRank }: { currentRank: number }) {
  return (
    <div className="flex items-center gap-1.5" role="img" aria-label={`Stage ${currentRank} of 5`}>
      {[0, 1, 2, 3, 4, 5].map((r) => (
        <span
          key={r}
          className={
            "h-1.5 rounded-full transition-all " +
            (r < currentRank
              ? "w-2.5 bg-leaf-300"
              : r === currentRank
                ? "w-6 bg-leaf-700"
                : "w-2.5 bg-rule-soft")
          }
        />
      ))}
    </div>
  );
}

function ReportSection({
  section,
  fields,
  history,
  options,
  isCurrent,
  defaultOpen,
}: {
  section: StageSectionConfig;
  fields: FieldConfig[];
  history: Record<string, FieldHistoryEntry[]>;
  options: Record<number, SelectOption[]>;
  isCurrent: boolean;
  defaultOpen: boolean;
}) {
  const [open, setOpen] = useState(defaultOpen);
  const headingId = useId();
  const panelId = useId();

  const cardClass = isCurrent
    ? "border-2 border-leaf-600 shadow-[0_1px_0_0_rgba(0,0,0,0.04),0_8px_24px_-12px_rgba(60,80,40,0.18)] bg-white/95"
    : "border border-rule bg-white/95 shadow-sm";

  return (
    <section
      aria-labelledby={headingId}
      className={"overflow-hidden rounded-lg transition " + cardClass}
    >
      <h2 id={headingId} className="m-0">
        <button
          type="button"
          onClick={() => setOpen((v) => !v)}
          aria-expanded={open}
          aria-controls={panelId}
          className={
            "group relative flex w-full items-center gap-4 px-5 py-4 text-left transition-colors sm:px-6 " +
            (isCurrent ? "bg-leaf-50/60" : "hover:bg-paper-2/60")
          }
        >
          <StageRankMark rank={section.rank} isCurrent={isCurrent} />
          <span className="flex-1 min-w-0">
            <span className="block font-display text-lg font-medium leading-tight tracking-tight text-ink sm:text-xl">
              {section.label}
            </span>
            <span className="mt-1 flex items-center gap-3 text-xs text-ink-mute">
              {isCurrent && (
                <span className="inline-flex items-center gap-1.5 rounded-full border border-clay-200 bg-clay-100/70 px-2 py-0.5 font-medium text-clay-700 uppercase tracking-[0.08em]">
                  <span className="h-1.5 w-1.5 rounded-full bg-clay-600" aria-hidden />
                  Current stage
                </span>
              )}
              <span className="tabular-nums">
                {fields.length} {fields.length === 1 ? "field" : "fields"} with entries
              </span>
            </span>
          </span>
          <Chevron open={open} />
        </button>
      </h2>

      <div
        id={panelId}
        role="region"
        aria-labelledby={headingId}
        hidden={!open}
        className="border-t border-rule-soft"
      >
        <div className="divide-y divide-rule-soft">
          {fields.map((f) => (
            <FieldHistoryRow
              key={f.name}
              field={f}
              entries={history[f.name] ?? []}
              options={options}
            />
          ))}
        </div>
      </div>
    </section>
  );
}

function StageRankMark({ rank, isCurrent }: { rank: number; isCurrent: boolean }) {
  return (
    <span aria-hidden className="relative inline-flex h-12 w-12 flex-shrink-0 items-center justify-center">
      <StageIcon
        rank={rank}
        className={
          "absolute inset-0 h-12 w-12 transition-opacity " +
          (isCurrent ? "text-leaf-700 opacity-100" : "text-leaf-600 opacity-50")
        }
      />
      <span
        className={
          "relative z-10 inline-flex h-5 w-5 items-center justify-center rounded-full text-[10px] font-semibold tabular-nums shadow-sm " +
          (isCurrent ? "bg-leaf-700 text-paper" : "bg-paper text-ink-soft border border-rule")
        }
        style={{ marginLeft: 28, marginTop: 28 }}
      >
        {rank}
      </span>
    </span>
  );
}

function Chevron({ open }: { open: boolean }) {
  return (
    <svg
      aria-hidden
      viewBox="0 0 20 20"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.5"
      strokeLinecap="round"
      className={"h-5 w-5 flex-shrink-0 text-ink-mute transition-transform duration-300 " + (open ? "rotate-180" : "")}
    >
      <path d="M5 8 L10 13 L15 8" />
    </svg>
  );
}

function FieldHistoryRow({
  field,
  entries,
  options,
}: {
  field: FieldConfig;
  entries: FieldHistoryEntry[];
  options: Record<number, SelectOption[]>;
}) {
  const [expanded, setExpanded] = useState(false);
  const latest = entries[0];
  const priorEntries = entries.slice(1);

  return (
    <div className="px-5 py-4 sm:px-7">
      <div className="flex flex-col gap-1.5 sm:flex-row sm:items-baseline sm:justify-between sm:gap-6">
        <div className="min-w-0 sm:max-w-[16rem]">
          <p className="text-sm font-medium text-ink">{field.label}</p>
          {field.help && (
            <p className="mt-0.5 text-xs leading-relaxed text-ink-mute">{field.help}</p>
          )}
        </div>
        <div className="flex-1 min-w-0 text-left sm:text-right">
          <p className="font-display text-lg font-medium leading-snug text-leaf-800 tabular-nums">
            <FormattedValue value={latest.value} field={field} options={options} />
          </p>
          <p className="mt-0.5 text-[11px] uppercase tracking-[0.1em] text-ink-mute">
            as of {formatShortDate(latest.date)}
            {priorEntries.length > 0 && (
              <>
                {" · "}
                <button
                  type="button"
                  onClick={() => setExpanded((v) => !v)}
                  aria-expanded={expanded}
                  className="font-medium normal-case tracking-normal text-leaf-700 hover:text-leaf-800 hover:underline focus:outline-none focus-visible:underline"
                >
                  {expanded ? "Hide" : `${priorEntries.length} earlier ${priorEntries.length === 1 ? "entry" : "entries"}`}
                </button>
              </>
            )}
          </p>
        </div>
      </div>

      {expanded && priorEntries.length > 0 && (
        <ol className="mt-3 space-y-1.5 border-l-2 border-rule-soft pl-4 sm:ml-auto sm:max-w-[24rem]">
          {priorEntries.map((e) => (
            <li
              key={e.activityId}
              className="flex items-baseline justify-between gap-4 text-sm"
            >
              <span className="text-[11px] uppercase tracking-[0.1em] text-ink-mute tabular-nums">
                {formatShortDate(e.date)}
              </span>
              <span className="text-right text-ink-soft tabular-nums">
                <FormattedValue value={e.value} field={field} options={options} />
              </span>
            </li>
          ))}
        </ol>
      )}
    </div>
  );
}

const currencyFmt = new Intl.NumberFormat("en-US", {
  style: "currency",
  currency: "USD",
  maximumFractionDigits: 2,
});

const numberFmt = new Intl.NumberFormat("en-US");

function FormattedValue({
  value,
  field,
  options,
}: {
  value: unknown;
  field: FieldConfig;
  options: Record<number, SelectOption[]>;
}) {
  if (value === null || value === undefined || value === "") return <>—</>;

  const opts: SelectOption[] | undefined = field.optionGroupId
    ? options[field.optionGroupId]
    : field.options;

  switch (field.type) {
    case "currency": {
      const n = typeof value === "number" ? value : Number(value);
      return <>{Number.isFinite(n) ? currencyFmt.format(n) : String(value)}</>;
    }
    case "percent": {
      const n = typeof value === "number" ? value : Number(value);
      return <>{Number.isFinite(n) ? `${n}%` : String(value)}</>;
    }
    case "number": {
      const n = typeof value === "number" ? value : Number(value);
      return <>{Number.isFinite(n) ? numberFmt.format(n) : String(value)}</>;
    }
    case "date":
      return <>{formatLongDate(String(value))}</>;
    case "boolean":
      return <>{value ? "Yes" : "No"}</>;
    case "select":
    case "readonly": {
      const v = String(value);
      const found = opts?.find((o) => o.value === v);
      return <>{found?.label ?? v}</>;
    }
    case "multiselect": {
      let parts: string[];
      if (Array.isArray(value)) {
        parts = value.map(String);
      } else {
        parts = String(value).split(/[|,]/).map((s) => s.trim()).filter(Boolean);
      }
      const labels = parts.map((p) => opts?.find((o) => o.value === p)?.label ?? p);
      return <>{labels.join(", ")}</>;
    }
    case "file":
      return <>{String(value)}</>;
    case "textarea":
    case "text":
    case "email":
    case "phone":
    default:
      return <>{String(value)}</>;
  }
}

function formatShortDate(iso: string): string {
  if (!iso) return "—";
  const d = new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
}

function formatLongDate(iso: string): string {
  if (!iso) return "—";
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(iso);
  const d = m
    ? new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]))
    : new Date(iso);
  if (Number.isNaN(d.getTime())) return iso;
  return d.toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
}

function computeDateRange(dates: string[]): { from: string; to: string } | null {
  if (dates.length === 0) return null;
  const times = dates
    .map((d) => new Date(d).getTime())
    .filter((t) => Number.isFinite(t));
  if (times.length === 0) return null;
  const min = new Date(Math.min(...times)).toISOString();
  const max = new Date(Math.max(...times)).toISOString();
  return { from: min, to: max };
}

function RailMarker({
  rank,
  state,
  nextState,
}: {
  rank: number;
  state: PathwayState;
  nextState?: PathwayState;
}) {
  return (
    <div
      aria-hidden
      className="pointer-events-none hidden md:block absolute -left-9 top-0 bottom-0 w-7"
    >
      {nextState && (
        <span
          className={
            "absolute left-1/2 -translate-x-1/2 top-11 -bottom-11 " +
            (nextState === "future"
              ? "w-0 border-l border-dashed border-rule"
              : "w-px bg-leaf-500/70")
          }
        />
      )}
      <MarkerCircle rank={rank} state={state} />
    </div>
  );
}

function MarkerCircle({ rank, state }: { rank: number; state: PathwayState }) {
  if (state === "past") {
    return (
      <span className="absolute left-1/2 -translate-x-1/2 top-6 inline-flex h-5 w-5 items-center justify-center rounded-full bg-leaf-700 text-paper shadow-sm">
        <svg viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="2.25" strokeLinecap="round" strokeLinejoin="round" className="h-2.5 w-2.5">
          <path d="M3 6.5l2 2 4-5" />
        </svg>
        <span className="sr-only">Stage {rank} (past)</span>
      </span>
    );
  }
  if (state === "current") {
    return (
      <span className="absolute left-1/2 -translate-x-1/2 top-6 inline-flex h-6 w-6 items-center justify-center rounded-full bg-leaf-700 text-paper text-[10px] font-semibold shadow-md ring-2 ring-leaf-100">
        {rank}
        <span className="sr-only">Stage {rank} (current)</span>
      </span>
    );
  }
  return (
    <span className="absolute left-1/2 -translate-x-1/2 top-6 inline-flex h-5 w-5 items-center justify-center rounded-full border border-dashed border-rule bg-paper text-ink-mute">
      <span className="text-[9px] font-medium tabular-nums">{rank}</span>
      <span className="sr-only">Stage {rank} (no entries)</span>
    </span>
  );
}

function MobileStem({ show, state }: { show: boolean; state: PathwayState }) {
  if (!show) return null;
  return (
    <div aria-hidden className="md:hidden -mt-4 mb-1.5 flex justify-center">
      <span
        className={
          "block h-4 " +
          (state === "future"
            ? "w-0 border-l border-dashed border-rule"
            : "w-px bg-leaf-500/70")
        }
      />
    </div>
  );
}

function LoadingState() {
  return (
    <div className="rounded-lg border border-rule bg-paper px-6 py-12 text-center">
      <div
        aria-hidden
        className="mx-auto mb-4 h-7 w-7 animate-spin rounded-full border-[1.5px] border-rule border-t-leaf-700"
      />
      <p className="font-display text-base text-ink-soft italic">Loading your activity report…</p>
    </div>
  );
}

function EmptyState() {
  return (
    <div className="rounded-lg border border-dashed border-rule bg-paper-2/30 px-6 py-10 text-center">
      <p className="font-display text-lg text-ink-soft">No entries on file yet.</p>
      <p className="mt-2 text-sm text-ink-mute">
        Your co-op&apos;s first check-in will appear here once it&apos;s submitted.
      </p>
    </div>
  );
}

function ErrorState({ message }: { message: string }) {
  return (
    <div role="alert" className="rounded-lg border-2 border-clay-200 bg-clay-100/30 px-6 py-7">
      <h2 className="font-display text-xl font-medium text-clay-700">
        We couldn&apos;t open your report.
      </h2>
      <p className="mt-3 text-sm leading-relaxed text-ink-soft">{message}</p>
      <p className="mt-4 text-sm text-ink-soft">
        If this keeps happening, please contact your engagement coordinator.
      </p>
    </div>
  );
}
