"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { useId, useState, useTransition } from "react";
import { Button, Card, buttonClass, inputClass } from "@/components/ui";
import { createReportScheduleAction, saveReportFilterAction } from "@/lib/actions/reports";
import { FREQUENCIES, OPERATORS, OPERATOR_LABEL, type ReportConfig } from "@/lib/reports/query";

interface Col { key: string; label: string; type: string; options?: readonly string[] }
export interface ReportViewData {
  entity: { key: string; label: string }; allColumns: Col[]; columns: { key: string; label: string }[]; rows: Record<string, string | number>[];
  total: number; page: number; perPage: number; truncated: boolean; config: ReportConfig;
}
type Panel = null | "filters" | "layout" | "save" | "schedule";
const PAGE_SIZES = [25, 50, 100];

const fmt = (c: Col | undefined, v: string | number | undefined) => {
  if (v === undefined || v === "") return "";
  if (c?.type === "date") { const d = new Date(String(v)); return Number.isNaN(d.getTime()) ? String(v) : d.toISOString().slice(0, 16).replace("T", " "); }
  return String(v);
};

/** ShowOff-style report page: table plus Edit Filters, Edit Layout and a More menu (export, save filter, schedule). */
export function ReportView({ siteId, base, result }: { siteId: string; base: string; result: ReportViewData }) {
  const uid = useId();
  const router = useRouter();
  const [panel, setPanel] = useState<Panel>(null);
  const [more, setMore] = useState(false);
  const [cfg, setCfg] = useState<ReportConfig>(result.config);
  const [name, setName] = useState("");
  const [freq, setFreq] = useState<(typeof FREQUENCIES)[number]>("WEEKLY");
  const [recipients, setRecipients] = useState("");
  const [msg, setMsg] = useState<{ ok: boolean; text: string } | null>(null);
  const [pending, start] = useTransition();
  const colOf = (k: string) => result.allColumns.find((c) => c.key === k);
  const shownKeys = cfg.columns.length ? cfg.columns : result.columns.map((c) => c.key);

  const url = (c: ReportConfig, page = 1, perPage = result.perPage) =>
    `${base}/run?entity=${encodeURIComponent(result.entity.key)}&config=${encodeURIComponent(JSON.stringify(c))}&page=${page}&perPage=${perPage}`;
  const apply = (c: ReportConfig) => { setPanel(null); router.push(url(c)); };
  const exportHref = `/api/reports/export?siteId=${encodeURIComponent(siteId)}&entity=${encodeURIComponent(result.entity.key)}&config=${encodeURIComponent(JSON.stringify(result.config))}`;
  const run = (f: () => Promise<{ ok: boolean; message?: string; error?: string }>, after?: () => void) => start(async () => { const r = await f(); setMsg({ ok: r.ok, text: r.ok ? (r.message ?? "Saved") : (r.error ?? "Failed") }); if (r.ok) { after?.(); } });
  const cleanCfg = (): ReportConfig => ({ ...cfg, filters: cfg.filters.filter((f) => f.value !== "") });

  const setFilter = (i: number, patch: Partial<ReportConfig["filters"][number]>) => setCfg({ ...cfg, filters: cfg.filters.map((f, j) => (j === i ? { ...f, ...patch } : f)) });
  const move = (key: string, dir: -1 | 1) => {
    const keys = [...shownKeys]; const i = keys.indexOf(key); const j = i + dir;
    if (i < 0 || j < 0 || j >= keys.length) return;
    [keys[i], keys[j]] = [keys[j]!, keys[i]!]; setCfg({ ...cfg, columns: keys });
  };
  const toggle = (key: string) => setCfg({ ...cfg, columns: shownKeys.includes(key) ? shownKeys.filter((k) => k !== key) : [...shownKeys, key] });
  const pages = Math.max(1, Math.ceil(result.total / result.perPage));
  const sel = `${inputClass}`;

  return (
    <>
      <div className="mb-3 flex flex-wrap items-center gap-2">
        <Button variant={panel === "filters" ? "primary" : "secondary"} aria-expanded={panel === "filters"} onClick={() => setPanel(panel === "filters" ? null : "filters")}>Edit Filters{result.config.filters.length ? ` (${result.config.filters.length})` : ""}</Button>
        <Button variant={panel === "layout" ? "primary" : "secondary"} aria-expanded={panel === "layout"} onClick={() => setPanel(panel === "layout" ? null : "layout")}>Edit Layout</Button>
        <div className="relative">
          <Button variant="secondary" aria-haspopup="menu" aria-expanded={more} onClick={() => setMore(!more)}>More</Button>
          {more ? (
            <div role="menu" aria-label="More report actions" className="absolute left-0 z-20 mt-1 w-48 rounded-md border border-border bg-card p-1 shadow-lg">
              <a role="menuitem" href={exportHref} download className="block rounded px-3 py-2 text-sm hover:bg-muted" onClick={() => setMore(false)}>Export CSV</a>
              <button role="menuitem" type="button" className="block w-full rounded px-3 py-2 text-left text-sm hover:bg-muted" onClick={() => { setMore(false); setPanel("save"); }}>Save filter</button>
              <button role="menuitem" type="button" className="block w-full rounded px-3 py-2 text-left text-sm hover:bg-muted" onClick={() => { setMore(false); setPanel("schedule"); }}>Schedule</button>
            </div>
          ) : null}
        </div>
        {result.config.filters.length || result.config.columns.length || result.config.sort ? <Link href={`${base}/run?entity=${encodeURIComponent(result.entity.key)}`} className={buttonClass("ghost")}>Reset</Link> : null}
      </div>
      <p role="status" aria-live="polite" className={msg ? (msg.ok ? "mb-3 text-sm text-success" : "mb-3 text-sm text-danger") : "sr-only"}>{msg?.text}</p>

      {panel === "filters" ? (
        <Card className="mb-4 p-4" role="region" aria-label="Edit filters">
          {cfg.filters.length === 0 ? <p className="mb-3 text-sm text-muted-foreground">No filters yet. Every row is shown.</p> : null}
          <div className="space-y-2">
            {cfg.filters.map((f, i) => {
              const c = colOf(f.column);
              return (
                <div key={i} className="grid gap-2 sm:grid-cols-[1fr_1fr_1fr_auto]">
                  <select aria-label={`Filter ${i + 1} column`} className={sel} value={f.column} onChange={(e) => setFilter(i, { column: e.target.value, value: "" })}>{result.allColumns.map((c2) => <option key={c2.key} value={c2.key}>{c2.label}</option>)}</select>
                  <select aria-label={`Filter ${i + 1} condition`} className={sel} value={f.op} onChange={(e) => setFilter(i, { op: e.target.value as typeof f.op })}>{OPERATORS.map((o) => <option key={o} value={o}>{OPERATOR_LABEL[o]}</option>)}</select>
                  {c?.type === "enum" && c.options ? (
                    <select aria-label={`Filter ${i + 1} value`} className={sel} value={f.value} onChange={(e) => setFilter(i, { value: e.target.value })}><option value="">Choose…</option>{c.options.map((o) => <option key={o} value={o}>{o}</option>)}</select>
                  ) : <input aria-label={`Filter ${i + 1} value`} type={c?.type === "date" ? "date" : c?.type === "number" ? "number" : "text"} maxLength={200} className={sel} value={f.value} onChange={(e) => setFilter(i, { value: e.target.value })} />}
                  <Button variant="ghost" aria-label={`Remove filter ${i + 1}`} onClick={() => setCfg({ ...cfg, filters: cfg.filters.filter((_, j) => j !== i) })}>Remove</Button>
                </div>
              );
            })}
          </div>
          <div className="mt-3 flex gap-2">
            <Button variant="secondary" disabled={cfg.filters.length >= 10} onClick={() => setCfg({ ...cfg, filters: [...cfg.filters, { column: result.allColumns[0]!.key, op: "contains", value: "" }] })}>Add filter</Button>
            <Button onClick={() => apply(cleanCfg())}>Apply filters</Button>
          </div>
        </Card>
      ) : null}

      {panel === "layout" ? (
        <Card className="mb-4 p-4" role="region" aria-label="Edit layout">
          <fieldset>
            <legend className="mb-2 text-sm font-medium">Columns (use the arrows to change the order)</legend>
            <ul className="space-y-1">
              {[...shownKeys, ...result.allColumns.map((c) => c.key).filter((k) => !shownKeys.includes(k))].map((k) => {
                const on = shownKeys.includes(k);
                return (
                  <li key={k} className="flex items-center gap-2 text-sm">
                    <input id={`${uid}-c-${k}`} type="checkbox" checked={on} onChange={() => toggle(k)} disabled={on && shownKeys.length === 1} />
                    <label htmlFor={`${uid}-c-${k}`} className="min-w-32">{colOf(k)?.label ?? k}</label>
                    {on ? (<><Button variant="ghost" aria-label={`Move ${colOf(k)?.label} up`} onClick={() => move(k, -1)}>↑</Button><Button variant="ghost" aria-label={`Move ${colOf(k)?.label} down`} onClick={() => move(k, 1)}>↓</Button></>) : null}
                  </li>
                );
              })}
            </ul>
          </fieldset>
          <div className="mt-3 grid max-w-md gap-2 sm:grid-cols-2">
            <div><label htmlFor={`${uid}-sort`} className="mb-1 block text-xs font-medium">Sort by</label>
              <select id={`${uid}-sort`} className={sel} value={cfg.sort?.column ?? ""} onChange={(e) => setCfg({ ...cfg, sort: e.target.value ? { column: e.target.value, desc: cfg.sort?.desc ?? false } : undefined })}><option value="">Default order</option>{result.allColumns.map((c) => <option key={c.key} value={c.key}>{c.label}</option>)}</select></div>
            <div><label htmlFor={`${uid}-dir`} className="mb-1 block text-xs font-medium">Direction</label>
              <select id={`${uid}-dir`} className={sel} disabled={!cfg.sort} value={cfg.sort?.desc ? "desc" : "asc"} onChange={(e) => cfg.sort && setCfg({ ...cfg, sort: { ...cfg.sort, desc: e.target.value === "desc" } })}><option value="asc">Ascending</option><option value="desc">Descending</option></select></div>
          </div>
          <div className="mt-3"><Button onClick={() => apply(cleanCfg())}>Apply layout</Button></div>
        </Card>
      ) : null}

      {panel === "save" || panel === "schedule" ? (
        <Card className="mb-4 p-4" role="region" aria-label={panel === "save" ? "Save filter" : "Schedule report"}>
          <div className="grid max-w-xl gap-3">
            <div><label htmlFor={`${uid}-name`} className="mb-1 block text-xs font-medium">{panel === "save" ? "Name this filter" : "Name this schedule"}</label>
              <input id={`${uid}-name`} className={sel} maxLength={120} value={name} onChange={(e) => setName(e.target.value)} /></div>
            {panel === "schedule" ? (
              <>
                <div><label htmlFor={`${uid}-freq`} className="mb-1 block text-xs font-medium">How often</label>
                  <select id={`${uid}-freq`} className={sel} value={freq} onChange={(e) => setFreq(e.target.value as typeof freq)}>{FREQUENCIES.map((f) => <option key={f} value={f}>{f[0] + f.slice(1).toLowerCase()}</option>)}</select></div>
                <div><label htmlFor={`${uid}-to`} className="mb-1 block text-xs font-medium">Email a notice to (optional, up to 10, separated by commas)</label>
                  <textarea id={`${uid}-to`} rows={2} className={sel} maxLength={2000} value={recipients} onChange={(e) => setRecipients(e.target.value)} aria-describedby={`${uid}-to-help`} />
                  <p id={`${uid}-to-help`} className="mt-1 text-xs text-muted-foreground">Recipients get a short notice. The CSV itself is kept under Schedule History because reports can hold personal data.</p></div>
              </>
            ) : null}
            <div className="flex gap-2">
              <Button disabled={pending || name.trim() === ""} onClick={() => run(async () => {
                const saved = await saveReportFilterAction(siteId, { entity: result.entity.key, name, config: cleanCfg() });
                if (panel === "save" || !saved.ok) return saved;
                const id = saved.data?.id ?? "";
                return createReportScheduleAction(siteId, { filterId: id, name, frequency: freq, recipients });
              }, () => { setPanel(null); setName(""); router.refresh(); })}>{pending ? "Saving…" : panel === "save" ? "Save filter" : "Save schedule"}</Button>
              <Button variant="ghost" onClick={() => setPanel(null)}>Cancel</Button>
            </div>
          </div>
        </Card>
      ) : null}

      <Card>
        {result.rows.length === 0 ? (
          <p className="px-4 py-10 text-center text-sm text-muted-foreground">No rows match{result.config.filters.length ? " these filters" : ""}.</p>
        ) : (
          <div className="overflow-x-auto" tabIndex={0} role="region" aria-label={`${result.entity.label} report table`}>
            <table className="w-full text-left text-sm">
              <caption className="sr-only">{result.entity.label} report</caption>
              <thead className="border-b border-border text-xs text-muted-foreground"><tr>{result.columns.map((c) => <th key={c.key} scope="col" className="whitespace-nowrap px-4 py-2 font-medium">{c.label}</th>)}</tr></thead>
              <tbody className="divide-y divide-border">
                {result.rows.map((r, i) => <tr key={i}>{result.columns.map((c) => <td key={c.key} className="max-w-xs truncate px-4 py-2" title={String(r[c.key] ?? "")}>{fmt(colOf(c.key), r[c.key])}</td>)}</tr>)}
              </tbody>
            </table>
          </div>
        )}
        <nav aria-label="Report pages" className="flex flex-wrap items-center justify-between gap-2 border-t border-border px-4 py-3 text-sm">
          <span className="text-muted-foreground">Page {result.page} of {pages} · {result.total} rows</span>
          <div className="flex items-center gap-2">
            <label htmlFor={`${uid}-pp`} className="text-xs">Rows per page</label>
            <select id={`${uid}-pp`} className="rounded-md border border-border bg-card px-2 py-1 text-sm" value={result.perPage} onChange={(e) => router.push(url(result.config, 1, Number(e.target.value)))}>{PAGE_SIZES.map((n) => <option key={n} value={n}>{n}</option>)}</select>
            {result.page > 1 ? <Link href={url(result.config, result.page - 1)} className={buttonClass("secondary")}>Previous</Link> : null}
            {result.page < pages ? <Link href={url(result.config, result.page + 1)} className={buttonClass("secondary")}>Next</Link> : null}
          </div>
        </nav>
      </Card>
      {result.truncated ? <p className="mt-3 text-xs text-muted-foreground">Only the most recent 5,000 rows are included.</p> : null}
    </>
  );
}
