"use client";

import React, { useEffect, useState, useMemo, useCallback } from "react";
import { useRouter } from "next/navigation";
import toast from "react-hot-toast";
import styles from "../commonstyle/dattabale.module.css";
import { EnterpriseLoader } from "../../../../components/loader/loader";
import { Pagination } from "../companies/Pagination";
import {
  FiRefreshCw,
  FiBarChart2,
  FiDownload,
  FiFileText,
  FiFilter,
  FiSearch,
  FiX,
  FiExternalLink,
  FiClipboard,
  FiCheckCircle,
  FiClock,
  FiPlusCircle,
  FiRotateCw,
  FiUploadCloud,
  FiFile,
} from "react-icons/fi";
import { getAuditAssignReport } from "@/lib/api/previous-nc.api";
import type { AuditAssignReportResponse } from "@/lib/api/previous-nc.api";
import {
  getAuditDetailReport,
  getAuditReportFileUrl,
  downloadAuditReport,
} from "@/lib/api/audit-report.api";
import type {
  AuditDetailResponse,
  AuditDetailRow,
  AuditDetailFilters,
} from "@/lib/api/audit-report.api";

// type → pill colors (matches the Previous NC audit-type look)
const TYPE_META: Record<string, { bg: string; color: string; border: string }> = {
  Initial: { bg: "#eef2ff", color: "#4338ca", border: "#c7d2fe" },
  Surveillance: { bg: "#fffbeb", color: "#b45309", border: "#fde68a" },
  Recertification: { bg: "#f0fdf4", color: "#15803d", border: "#bbf7d0" },
};
const SOURCE_META: Record<string, { bg: string; color: string }> = {
  QRS: { bg: "#eef2ff", color: "#4f46e5" },
  TQS: { bg: "#ecfeff", color: "#0891b2" },
  "QRS & TQS": { bg: "#f0fdf4", color: "#15803d" },
};

const fmt = (n: number) => (n ?? 0).toLocaleString();
const monthName = (m: number) =>
  ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"][m] || "";
const fmtDate = (d: string | null) => {
  if (!d) return "—";
  const dt = new Date(d);
  if (isNaN(dt.getTime())) return d;
  return dt.toLocaleDateString("en-GB", { day: "2-digit", month: "short", year: "numeric" });
};

function useDebounce<T>(value: T, delay: number): T {
  const [d, setD] = useState(value);
  useEffect(() => {
    const t = setTimeout(() => setD(value), delay);
    return () => clearTimeout(t);
  }, [value, delay]);
  return d;
}

export default function AuditReportDatatablePage() {
  const router = useRouter();

  const [data, setData] = useState<AuditDetailResponse | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [downloading, setDownloading] = useState<null | "excel" | "pdf">(null);

  const [optionsData, setOptionsData] = useState<AuditAssignReportResponse | null>(null);
  // 🆕 transfer modal state
  const [transferRow, setTransferRow] = useState<AuditDetailRow | null>(null);
  const [transferTo, setTransferTo] = useState("");
  const [transferring, setTransferring] = useState(false);

  // auditor list (scheme user_id + name) — only "QRS & TQS" rows carry the scheme id
  // 🆕 auditor list for transfers, loaded from scheme_dbs s via the backend
  const [auditorUsers, setAuditorUsers] = useState<{ user_id: number; auditor: string }[]>([]);
  useEffect(() => {
    if (!data?.can_manage) return;
    if (auditorUsers.length > 0) return; // already loaded
    import("@/lib/api/audit-report.api").then(({ getTransferAuditors }) =>
      getTransferAuditors()
        .then((users) => setAuditorUsers(users.map((u) => ({ user_id: u.user_id, auditor: u.name }))))
        .catch(() => {}),
    );
  }, [data?.can_manage, auditorUsers.length]);

  const doTransfer = async () => {
    if (!transferRow || !transferTo) return;
    setTransferring(true);
    try {
      const { transferAudit } = await import("@/lib/api/audit-report.api");
      await transferAudit({
        source: transferRow.source,
        table: transferRow.table,
        record_id: transferRow.record_id,
        from_auditor_id: transferRow.auditor_id,
        to_user_id: Number(transferTo),
      });
      toast.success("Audit transferred");
      setTransferRow(null);
      setTransferTo("");
      fetchData();
    } catch (err: any) {
      toast.error(err?.message ?? "Transfer failed");
    } finally {
      setTransferring(false);
    }
  };
  // filters
  const [searchTerm, setSearchTerm] = useState("");
  const [filterSource, setFilterSource] = useState("");
  const [filterAuditor, setFilterAuditor] = useState("");
  const [filterYear, setFilterYear] = useState("");
  const [filterMonthNum, setFilterMonthNum] = useState("");
  const [filterType, setFilterType] = useState("");
  const [filterStatus, setFilterStatus] = useState("");
  const [filterPhase, setFilterPhase] = useState("");
  const debouncedSearch = useDebounce(searchTerm, 400);

  // paging
  const [currentPage, setCurrentPage] = useState(1);
  const [itemsPerPage, setItemsPerPage] = useState(10);

  const hasActiveFilter = !!(
    filterSource || filterAuditor || filterYear || filterMonthNum || filterType || filterStatus || filterPhase || debouncedSearch
  );

  const currentFilters: AuditDetailFilters = useMemo(
    () => ({
      source: (filterSource || undefined) as AuditDetailFilters["source"],
      auditor: filterAuditor || undefined,
      year: filterYear || undefined,
      month: filterMonthNum ? String(parseInt(filterMonthNum, 10)) : undefined,
      audit_type: (filterType || undefined) as AuditDetailFilters["audit_type"],
      report_status: (filterStatus || undefined) as AuditDetailFilters["report_status"],
      phase: (filterPhase || undefined) as AuditDetailFilters["phase"],
      search: debouncedSearch || undefined,
    }),
    [filterSource, filterAuditor, filterYear, filterMonthNum, filterType, filterStatus, filterPhase, debouncedSearch],
  );

  // dropdown options (from the assign report — same source as the screenshot counts)
  useEffect(() => {
    getAuditAssignReport().then(setOptionsData).catch(() => { });
  }, []);

  const [refreshKey, setRefreshKey] = useState(0);

  const fetchData = () => setRefreshKey((k) => k + 1);   // Refresh button still works

  useEffect(() => {
    let cancelled = false;   // becomes true if a newer request starts
    (async () => {
      setLoading(true);
      setError(null);
      try {
        const res = await getAuditDetailReport({ ...currentFilters, page: currentPage, limit: itemsPerPage });
        if (!cancelled) setData(res);   // only accept the result if still the latest request
      } catch (err: any) {
        if (!cancelled) setError(err?.message ?? "Failed to load audit report");
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, [currentFilters, currentPage, itemsPerPage, refreshKey]);

  useEffect(() => { setCurrentPage(1); }, [currentFilters]);

  // cascading dropdown lists
  const filterOptions = useMemo(() => {
    const rows = optionsData?.rows ?? [];

    // always include the three known sources, plus anything the assign report has
    const sourceSet = new Set<string>(["QRS", "TQS", "QRS & TQS"]);
    rows.forEach((r) => r.source && sourceSet.add(r.source));
    const sources = Array.from(sourceSet).sort();

    const auditors = Array.from(
      new Set(rows.filter((r) => !filterSource || r.source === filterSource).map((r) => r.auditor)),
    ).sort((a, b) => a.localeCompare(b));
    const months = new Set<string>();
    rows.forEach((r) => r.months.forEach((m) => m.month && months.add(m.month)));
    const years = Array.from(new Set(Array.from(months).map((m) => m.split("-")[0])))
      .filter((y) => /^\d{4}$/.test(y))
      .sort((a, b) => Number(b) - Number(a));
    const monthNums = Array.from({ length: 12 }, (_, i) => String(i + 1).padStart(2, "0"));
    return { sources, auditors, years, monthNums };
  }, [optionsData, filterSource]);

  useEffect(() => {
    if (filterAuditor && !filterOptions.auditors.includes(filterAuditor)) setFilterAuditor("");
  }, [filterOptions.auditors, filterAuditor]);

  const clearFilters = () => {
    setSearchTerm(""); setFilterSource(""); setFilterAuditor("");
    setFilterYear(""); setFilterMonthNum(""); setFilterType(""); setFilterStatus(""); setFilterPhase("");
  };

  const handleDownload = async (format: "excel" | "pdf") => {
    setDownloading(format);
    try {
      await downloadAuditReport(format, currentFilters);
      toast.success(`${format === "excel" ? "Excel" : "PDF"} report downloaded`);
    } catch (err: any) {
      toast.error(err?.message ?? "Download failed");
    } finally {
      setDownloading(null);
    }
  };

  const openFile = async (
    row: AuditDetailRow,
    kind: 1 | 2 | "attendance" | "support",
  ) => {
    const uploaded =
      kind === 1
        ? row.stage1_uploaded
        : kind === 2
          ? row.stage2_uploaded
          : kind === "attendance"
            ? row.attendance_uploaded
            : row.support_uploaded;
    if (!uploaded) return;
    try {
      // Attendance + supporting docs live in the scheme "audit documents"
      // storage — always fetched via the audit-documents blob endpoint.
      if (kind === "attendance" || kind === "support") {
        const { fetchAuditDocumentBlob } = await import("@/lib/api/audit-documents.api");
        const docType = kind === "attendance" ? "attendance" : "support_docs";
        const url = await fetchAuditDocumentBlob(row.record_id, docType);
        window.open(url, "_blank", "noopener");
        return;
      }
      if (row.source === "QRS & TQS") {
        const { fetchAuditDocumentBlob } = await import("@/lib/api/audit-documents.api");
        const docType = kind === 1 ? "stage1_report" : "stage2_report";
        const url = await fetchAuditDocumentBlob(row.record_id, docType);
        window.open(url, "_blank", "noopener");
      } else {
        const { url } = await getAuditReportFileUrl({ source: row.source, table: row.table, id: row.record_id, stage: kind });
        window.open(url, "_blank", "noopener");
      }
    } catch (err: any) {
      toast.error(err?.message ?? "Could not open file");
    }
  };

  const s = data?.summary;
  const rows = data?.rows ?? [];
  const total = data?.total ?? 0;
  const totalPages = data?.totalPages ?? 1;

  if (error)
    return (
      <div className={styles.errorContainer}>
        <div className={styles.errorIcon}>⚠️</div>
        <h3 className={styles.errorTitle}>Error</h3>
        <p className={styles.errorMessage}>{error}</p>
        <button className={styles.errorButton} onClick={fetchData}>Retry</button>
      </div>
    );

  const thStyle: React.CSSProperties = {
    padding: "12px 10px", textAlign: "left", fontSize: 10, fontWeight: 800, color: "#475569",
    textTransform: "uppercase", letterSpacing: "0.06em", background: "#f8fafc", borderBottom: "1px solid #e2e8f0",
    whiteSpace: "nowrap",
  };
  const tdStyle: React.CSSProperties = { padding: "12px 10px", fontSize: 12.5, color: "#374151", verticalAlign: "top", whiteSpace: "nowrap" };

  return (
    <div className={styles.container}>
      {/* ── Header (same purple shell as Previous NC) ── */}
      <div className={styles.header}>
        <div className={styles.headerLeft}>
          <h1 className={styles.title}>Audit Report</h1>
          <p className={styles.subtitle}>
            Per-audit detail across QRS &amp; TQS
            {total > 0 ? ` · ${total.toLocaleString()} audits` : ""}
          </p>
        </div>
        <div className={styles.headerRight}>
          <button
            className={styles.btnSecondary}
            onClick={() => router.push("/modules/previous-nc/audit-assign-report")}
            style={{ background: "rgba(255,255,255,0.15)", color: "#fff", border: "1px solid rgba(255,255,255,0.3)", display: "inline-flex", alignItems: "center", gap: 6 }}
            title="Auditor summary report"
          >
            <FiBarChart2 size={14} /> Summary Report
          </button>
          <button
            className={styles.btnSecondary}
            onClick={() => handleDownload("excel")}
            disabled={downloading !== null}
            style={{ background: "rgba(255,255,255,0.15)", color: "#fff", border: "1px solid rgba(255,255,255,0.3)", display: "inline-flex", alignItems: "center", gap: 6 }}
            title="Download Excel report"
          >
            <FiDownload size={14} /> {downloading === "excel" ? "Exporting…" : "Excel"}
          </button>
          <button
            className={styles.btnSecondary}
            onClick={fetchData}
            style={{ background: "rgba(255,255,255,0.15)", color: "#fff", border: "1px solid rgba(255,255,255,0.3)", display: "inline-flex", alignItems: "center", gap: 6 }}
            title="Refresh"
          >
            <FiRefreshCw size={14} /> Refresh
          </button>
        </div>
      </div>

      {/* ── Summary cards ── */}
      <div style={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: "14px 16px", marginBottom: 12 }}>
        <GroupLabel>Overview</GroupLabel>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 12, marginBottom: 14 }}>
          <KpiCard icon={<FiClipboard />} grad={["#2563eb", "#1e40af"]} label="Total Audit Assign" value={fmt(s?.total_assigned ?? 0)} caption="all audits" />
          <KpiCard icon={<FiCheckCircle />} grad={["#0d9488", "#065f46"]} label="Audit Performed" value={fmt(s?.conducted_count ?? 0)} caption="conducted (past)" />
          <KpiCard icon={<FiClock />} grad={["#7c3aed", "#5b21b6"]} label="Upcoming Audits" value={fmt(s?.scheduled_count ?? 0)} caption="report not due yet" />
        </div>
      </div>
      <div style={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: "14px 16px", marginBottom: 12 }}>

        <GroupLabel>Audits performed by type</GroupLabel>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(180px, 1fr))", gap: 12, marginBottom: 14 }}>
          <KpiCard icon={<FiPlusCircle />} grad={["#4f46e5", "#3730a3"]} label="Initial" value={fmt(s?.initial_count ?? 0)} caption="performed" />
          <KpiCard icon={<FiSearch />} grad={["#d97706", "#92400e"]} label="Surveillance (Due)" value={fmt(s?.surveillance_count ?? 0)} caption="performed" />
          <KpiCard icon={<FiRotateCw />} grad={["#059669", "#065f46"]} label="Recertification (Due)" value={fmt(s?.recert_count ?? 0)} caption="performed" />
        </div>
      </div>
      <div style={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: "14px 16px", marginBottom: 12 }}>

        <GroupLabel>Report status (performed audits only)</GroupLabel>
        <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))", gap: 12, marginBottom: 14 }}>
          <ReportKpiCard icon={<FiUploadCloud />} grad={["#0ea5e9", "#0369a1"]} ring="#0ea5e9" label="Stage 1 Report" uploaded={s?.stage1_uploaded ?? 0} missing={s?.stage1_missing ?? 0} />
          <ReportKpiCard icon={<FiFileText />} grad={["#10b981", "#047857"]} ring="#10b981" label="Stage 2 Report (completed)" uploaded={s?.stage2_uploaded ?? 0} missing={s?.stage2_missing ?? 0} />
        </div>
      </div>

      {/* clarifying note */}
      <div style={{ display: "flex", alignItems: "flex-start", gap: 8, background: "#eff6ff", border: "1px solid #bfdbfe", borderRadius: 8, padding: "10px 14px", marginBottom: 16, fontSize: 12.5, color: "#1e40af", lineHeight: 1.5 }}>
        <span style={{ fontWeight: 800 }}>ℹ️</span>
        <span>
          Type cards = audits <strong>performed</strong>. Completion (uploaded / missing) is in the <strong>Stage&nbsp;1 / Stage&nbsp;2</strong> cards. Upcoming audits aren&apos;t counted as missing.
        </span>
      </div>

      {/* ── Filter bar (same look as Previous NC) ── */}
      <div style={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: "14px 16px", marginBottom: 12 }}>
        <div style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 10 }}>
          <div style={{ position: "relative", flex: 1 }}>
            <FiSearch size={15} style={{ position: "absolute", left: 12, top: "50%", transform: "translateY(-50%)", color: "#94a3b8" }} />
            <input
              value={searchTerm}
              onChange={(e) => setSearchTerm(e.target.value)}
              placeholder="Search by client name…"
              style={{ width: "100%", padding: "10px 12px 10px 36px", border: "1px solid #e2e8f0", borderRadius: 8, fontSize: 13, outline: "none" }}
            />
          </div>
          <button
            onClick={() => handleDownload("excel")}
            disabled={downloading !== null}
            title="Download Excel report"
            style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6, height: 40, padding: "0 12px", border: "1px solid #bbf7d0", background: "#f0fdf4", color: "#15803d", borderRadius: 8, fontSize: 13, fontWeight: 700, cursor: downloading ? "not-allowed" : "pointer", opacity: downloading === "pdf" ? 0.5 : 1 }}
          >
            <FiDownload size={16} /> {downloading === "excel" ? "…" : "Excel"}
          </button>
          <button
            onClick={() => handleDownload("pdf")}
            disabled={downloading !== null}
            title="Download PDF report"
            style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: 6, height: 40, padding: "0 12px", border: "1px solid #fecaca", background: "#fef2f2", color: "#dc2626", borderRadius: 8, fontSize: 13, fontWeight: 700, cursor: downloading ? "not-allowed" : "pointer", opacity: downloading === "excel" ? 0.5 : 1 }}
          >
            <FiFile size={16} /> {downloading === "pdf" ? "…" : "PDF"}
          </button>
        </div>
        <div style={{ display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap" }}>
          <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 12, fontWeight: 700, color: "#0f766e" }}>
            <FiFilter size={13} /> FILTERS
          </span>
          <Select value={filterSource} onChange={setFilterSource} placeholder="All Sources"
            options={filterOptions.sources.map((o) => ({ value: o, label: o }))} />
          <Select value={filterAuditor} onChange={setFilterAuditor}
            placeholder={`All Auditors${filterOptions.auditors.length ? ` (${filterOptions.auditors.length})` : ""}`}
            options={filterOptions.auditors.map((o) => ({ value: o, label: o }))} minWidth={200} />
          <Select value={filterType} onChange={setFilterType} placeholder="All Audit Types"
            options={[{ value: "Initial", label: "Initial" }, { value: "Surveillance", label: "Surveillance" }, { value: "Recertification", label: "Recertification" }]} />
          <Select value={filterStatus} onChange={setFilterStatus} placeholder="Any Report Status"
            options={[
              { value: "s1_missing", label: "Stage 1 missing" },
              { value: "s2_missing", label: "Stage 2 missing" },
              { value: "s1_uploaded", label: "Stage 1 uploaded" },
              { value: "s2_uploaded", label: "Stage 2 uploaded" },
            ]} minWidth={160} />
          <Select value={filterPhase} onChange={setFilterPhase} placeholder="Conducted + Upcoming"
            options={[
              { value: "conducted", label: "Conducted (past)" },
              { value: "upcoming", label: "Scheduled (future)" },
            ]} minWidth={170} />
          <Select value={filterYear} onChange={setFilterYear} placeholder="All Years"
            options={filterOptions.years.map((o) => ({ value: o, label: o }))} minWidth={110} />
          <Select value={filterMonthNum} onChange={setFilterMonthNum} placeholder="All Months"
            options={filterOptions.monthNums.map((o) => ({ value: o, label: monthName(parseInt(o, 10) - 1) }))} minWidth={130} />
          {hasActiveFilter && (
            <button onClick={clearFilters}
              style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "8px 12px", border: "1px solid #e2e8f0", borderRadius: 8, background: "#fff", color: "#64748b", fontSize: 12, fontWeight: 700, cursor: "pointer" }}>
              <FiX size={12} /> Clear
            </button>
          )}
        </div>
      </div>

      {/* ── Count strip (same as Previous NC) ── */}
      {data && (
        <div style={{ padding: "10px 16px", background: "linear-gradient(90deg, #f0fdfa 0%, #f8fafc 100%)", border: "1px solid #99f6e4", borderRadius: 8, marginBottom: 12, display: "flex", alignItems: "center", justifyContent: "space-between", fontSize: 13, color: "#0f766e" }}>
          <span>
            📋 Showing <strong>{total === 0 ? 0 : (currentPage - 1) * itemsPerPage + 1}–{Math.min(currentPage * itemsPerPage, total)}</strong> of <strong>{total.toLocaleString()}</strong> audits
          </span>
          {hasActiveFilter && (
            <span style={{ fontSize: 11, fontWeight: 700, color: "#0f766e", background: "#fff", padding: "3px 10px", borderRadius: 99, border: "1px solid #99f6e4" }}>
              Filtered
            </span>
          )}
        </div>
      )}

      {/* ── Table ── */}
      <div className={styles.tableWrapper}>
        <table className={styles.table} style={{ width: "100%" }}>
          <thead>
            <tr>
              <th style={thStyle}>Client ID</th>
              <th style={thStyle}>Client</th>
              <th style={thStyle}>Auditor</th>
              <th style={thStyle}>Audit Date</th>
              <th style={thStyle}>Audit Type</th>
              <th style={{ ...thStyle, textAlign: "center" }}>Stage 1 Report</th>
              <th style={{ ...thStyle, textAlign: "center" }}>Stage 2 Report</th>
              <th style={{ ...thStyle, textAlign: "center" }}>Attendance</th>
              <th style={{ ...thStyle, textAlign: "center" }}>Supporting Docs</th>

              {data?.can_manage && <th style={{ ...thStyle, textAlign: "center" }}>Actions</th>}
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr><td colSpan={data?.can_manage ? 11 : 10} style={{ textAlign: "center", padding: "60px" }}><EnterpriseLoader /></td></tr>
            ) : rows.length === 0 ? (
              <tr>
                <td colSpan={data?.can_manage ? 11 : 10} style={{ textAlign: "center", padding: "60px" }}>
                  <div style={{ fontSize: 36 }}>📋</div>
                  <h3 style={{ margin: "12px 0 4px", color: "#111827" }}>No audits found</h3>
                  <p style={{ color: "#6b7280", margin: 0 }}>{hasActiveFilter ? "No audits match your filters." : "No audit data available."}</p>
                </td>
              </tr>
            ) : (
              rows.map((r) => (
                <tr key={`${r.source}-${r.table}-${r.record_id}-${r.audit_type}`} style={{ borderTop: "1px solid #f1f5f9" }}>
                  <td style={{ ...tdStyle, fontFamily: "'JetBrains Mono', monospace", fontSize: 11, color: "#0f766e", fontWeight: 600 }}>{r.record_id}</td>
                  <td style={{ ...tdStyle, maxWidth: 260, whiteSpace: "normal" }}>
                    <span style={{ fontWeight: 600, fontSize: 13, color: "#111827" }} title={r.client_name ?? ""}>{r.client_name ?? "—"}</span>
                  </td>
                  <td style={tdStyle}>{r.auditor}</td>
                  <td style={tdStyle}>
                    <div style={{ display: "flex", alignItems: "center", gap: 6 }}>
                      {fmtDate(r.audit_date)}
                      {!r.conducted && (
                        <span style={{ fontSize: 9.5, fontWeight: 800, padding: "1px 6px", borderRadius: 99, background: "#f1f5f9", color: "#64748b", textTransform: "uppercase", letterSpacing: 0.4 }}>
                          Scheduled
                        </span>
                      )}
                    </div>
                  </td>
                  <td style={tdStyle}>
                    <TypePill type={r.audit_type} />
                  </td>
                  <td style={{ ...tdStyle, textAlign: "center" }}><StageLink uploaded={r.stage1_uploaded} conducted={r.conducted} onOpen={() => openFile(r, 1)} /></td>
                  <td style={{ ...tdStyle, textAlign: "center" }}><StageLink uploaded={r.stage2_uploaded} conducted={r.conducted} onOpen={() => openFile(r, 2)} /></td>
                  <td style={{ ...tdStyle, textAlign: "center" }}><DocLink uploaded={r.attendance_uploaded} onOpen={() => openFile(r, "attendance")} /></td>
                  <td style={{ ...tdStyle, textAlign: "center" }}><DocLink uploaded={r.support_uploaded} onOpen={() => openFile(r, "support")} /></td>
                  <td style={{ ...tdStyle, textAlign: "center" }}>
                    <span style={{ padding: "2px 8px", borderRadius: 99, background: (SOURCE_META[r.source] || { bg: "#f1f5f9" }).bg, color: (SOURCE_META[r.source] || { color: "#475569" }).color, fontSize: 10, fontWeight: 700 }}>📁 {r.source}</span>
                  </td>
                  {data?.can_manage && (
                    <td style={{ ...tdStyle, textAlign: "center" }}>
                      <button onClick={() => { setTransferTo(""); setTransferRow(r); }} title="Transfer to another auditor"
                        style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 6, border: "1px solid #c7d2fe", background: "#eef2ff", color: "#4338ca", fontSize: 11, fontWeight: 700, cursor: "pointer" }}>
                        ⇄ Transfer
                      </button>
                    </td>
                  )}
                </tr>
              ))
            )}
          </tbody>
        </table>
      </div>

      {data && total > 0 && (
        <Pagination
          currentPage={currentPage}
          setCurrentPage={setCurrentPage}
          totalPages={totalPages}
          startIndex={(currentPage - 1) * itemsPerPage + 1}
          endIndex={Math.min(currentPage * itemsPerPage, total)}
          sortedDataLength={total}
          itemsPerPage={itemsPerPage}
          setItemsPerPage={(v: number) => { setCurrentPage(1); setItemsPerPage(v); }}
        />
      )}
      {/* 🆕 transfer modal */}
      {transferRow && (
        <div onClick={() => setTransferRow(null)}
          style={{ position: "fixed", inset: 0, background: "rgba(15,23,42,0.45)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1000 }}>
          <div onClick={(e) => e.stopPropagation()}
            style={{ background: "#fff", borderRadius: 12, padding: 20, width: 380, maxWidth: "90vw", boxShadow: "0 20px 50px rgba(0,0,0,0.25)" }}>
            <h3 style={{ margin: "0 0 4px", fontSize: 15 }}>Transfer audit</h3>
            <p style={{ margin: "0 0 14px", fontSize: 12.5, color: "#64748b" }}>
              <strong>{transferRow.client_name ?? "—"}</strong> — currently assigned to <strong>{transferRow.auditor}</strong>
            </p>
            <Select value={transferTo} onChange={setTransferTo} placeholder="Select new auditor…"
              options={auditorUsers
                .filter((u) => u.auditor !== transferRow.auditor)
                .map((u) => ({ value: String(u.user_id), label: u.auditor }))}
              minWidth={330} />
            <div style={{ display: "flex", gap: 8, justifyContent: "flex-end", marginTop: 16 }}>
              <button onClick={() => setTransferRow(null)}
                style={{ padding: "8px 14px", border: "1px solid #e2e8f0", borderRadius: 8, background: "#fff", fontSize: 12.5, fontWeight: 700, cursor: "pointer", color: "#64748b" }}>
                Cancel
              </button>
              <button onClick={doTransfer} disabled={!transferTo || transferring}
                style={{ padding: "8px 14px", border: "none", borderRadius: 8, background: !transferTo ? "#c7d2fe" : "#4f46e5", color: "#fff", fontSize: 12.5, fontWeight: 700, cursor: !transferTo || transferring ? "not-allowed" : "pointer" }}>
                {transferring ? "Transferring…" : "Transfer"}
              </button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}


// ── sub-components ──
function GroupLabel({ children }: { children: React.ReactNode }) {
  return (
    <div style={{ fontSize: 11, fontWeight: 700, color: "#94a3b8", textTransform: "uppercase", letterSpacing: "0.05em", margin: "0 0 6px 2px" }}>
      {children}
    </div>
  );
}

function KpiCard({ icon, grad, label, value, caption }: { icon: React.ReactNode; grad: [string, string]; label: string; value: string; caption?: string }) {
  return (
    <div style={{ position: "relative", overflow: "hidden", background: `linear-gradient(135deg, ${grad[0]} 0%, ${grad[1]} 100%)`, borderRadius: 12, padding: "13px 15px", color: "#fff", boxShadow: "0 3px 10px rgba(15,23,42,0.12)" }}>
      <div aria-hidden style={{ position: "absolute", right: -8, top: -6, fontSize: 64, opacity: 0.12, lineHeight: 1, pointerEvents: "none" }}>{icon}</div>
      <div style={{ display: "flex", alignItems: "center", gap: 9 }}>
        <div style={{ width: 34, height: 34, borderRadius: 9, background: "rgba(255,255,255,0.2)", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 16, flexShrink: 0 }}>
          {icon}
        </div>
        <span style={{ fontSize: 12, fontWeight: 600, letterSpacing: "0.02em", opacity: 0.95 }}>{label}</span>
      </div>
      <div style={{ fontSize: 26, fontWeight: 800, lineHeight: 1, margin: "9px 0 2px" }}>{value}</div>
      {caption && <div style={{ fontSize: 11, opacity: 0.85 }}>{caption}</div>}
    </div>
  );
}

function ReportKpiCard({ icon, grad, ring, label, uploaded, missing }: { icon: React.ReactNode; grad: [string, string]; ring: string; label: string; uploaded: number; missing: number }) {
  const total = uploaded + missing;
  const pctUp = total > 0 ? Math.round((uploaded / total) * 100) : 0;
  const R = 24;
  const C = 2 * Math.PI * R;
  const dash = (pctUp / 100) * C;
  return (
    <div style={{ background: "#fff", border: "1px solid #e2e8f0", borderRadius: 12, padding: "13px 15px", boxShadow: "0 2px 8px rgba(15,23,42,0.05)" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 9, marginBottom: 11 }}>
        <div style={{ width: 32, height: 32, borderRadius: 9, background: `linear-gradient(135deg, ${grad[0]} 0%, ${grad[1]} 100%)`, color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 15, flexShrink: 0, boxShadow: `0 2px 6px ${grad[1]}40` }}>
          {icon}
        </div>
        <div style={{ fontSize: 12.5, fontWeight: 700, color: "#1e293b" }}>{label}</div>
      </div>

      <div style={{ display: "flex", alignItems: "center", gap: 14 }}>
        {/* circular progress ring */}
        <div style={{ position: "relative", width: 62, height: 62, flexShrink: 0 }}>
          <svg width="62" height="62" viewBox="0 0 62 62">
            <circle cx="31" cy="31" r={R} fill="none" stroke="#eef2f7" strokeWidth="7" />
            <circle cx="31" cy="31" r={R} fill="none" stroke={ring} strokeWidth="7" strokeLinecap="round"
              strokeDasharray={`${dash} ${C - dash}`} transform="rotate(-90 31 31)" />
          </svg>
          <div style={{ position: "absolute", inset: 0, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center" }}>
            <div style={{ fontSize: 15, fontWeight: 800, color: "#0f172a", lineHeight: 1 }}>{pctUp}%</div>
            <div style={{ fontSize: 8, color: "#94a3b8", fontWeight: 600, textTransform: "uppercase", letterSpacing: 0.3 }}>done</div>
          </div>
        </div>

        {/* uploaded / missing legend */}
        <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: 6 }}>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", background: "#f0fdf4", border: "1px solid #bbf7d0", borderRadius: 8, padding: "6px 10px" }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 11.5, fontWeight: 700, color: "#15803d" }}>
              <span style={{ width: 8, height: 8, borderRadius: "50%", background: "#16a34a", display: "inline-block" }} /> Uploaded
            </span>
            <span style={{ fontSize: 17, fontWeight: 800, color: "#16a34a", lineHeight: 1 }}>{fmt(uploaded)}</span>
          </div>
          <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", background: "#fef2f2", border: "1px solid #fecaca", borderRadius: 8, padding: "6px 10px" }}>
            <span style={{ display: "inline-flex", alignItems: "center", gap: 6, fontSize: 11.5, fontWeight: 700, color: "#b91c1c" }}>
              <span style={{ width: 8, height: 8, borderRadius: "50%", background: "#dc2626", display: "inline-block" }} /> Missing
            </span>
            <span style={{ fontSize: 17, fontWeight: 800, color: "#dc2626", lineHeight: 1 }}>{fmt(missing)}</span>
          </div>
        </div>
      </div>

      <div style={{ fontSize: 10.5, color: "#94a3b8", marginTop: 9, fontWeight: 600, textAlign: "center" }}>
        {fmt(uploaded)} of {fmt(total)} performed audits have this report
      </div>
    </div>
  );
}

function TypePill({ type }: { type: string }) {
  const m = TYPE_META[type] || { bg: "#f1f5f9", color: "#475569", border: "#cbd5e1" };
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 4, padding: "4px 10px", borderRadius: 8, background: m.bg, color: m.color, border: `1px solid ${m.border}`, fontSize: 11, fontWeight: 700, whiteSpace: "nowrap" }}>
      {type}
    </span>
  );
}
function DocLink({ uploaded, onOpen }: { uploaded: boolean; onOpen: () => void }) {
  if (uploaded) {
    return (
      <button onClick={onOpen} title="Open document"
        style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 6, border: "1px solid #86efac", background: "#f0fdf4", color: "#15803d", fontSize: 11, fontWeight: 700, cursor: "pointer" }}>
        <FiFileText size={12} /> View <FiExternalLink size={10} style={{ opacity: 0.7 }} />
      </button>
    );
  }
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 6, border: "1px solid #e2e8f0", background: "#f8fafc", color: "#94a3b8", fontSize: 11, fontWeight: 700 }}>
      —
    </span>
  );
}
function StageLink({ uploaded, conducted, onOpen }: { uploaded: boolean; conducted: boolean; onOpen: () => void }) {
  if (uploaded) {
    return (
      <button onClick={onOpen} title="Open report"
        style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 6, border: "1px solid #86efac", background: "#f0fdf4", color: "#15803d", fontSize: 11, fontWeight: 700, cursor: "pointer" }}>
        <FiFileText size={12} /> View <FiExternalLink size={10} style={{ opacity: 0.7 }} />
      </button>
    );
  }
  if (!conducted) {
    // future audit — report not expected yet
    return (
      <span title="Audit date is in the future" style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 6, border: "1px solid #e2e8f0", background: "#f8fafc", color: "#64748b", fontSize: 11, fontWeight: 700 }}>
        Scheduled
      </span>
    );
  }
  return (
    <span style={{ display: "inline-flex", alignItems: "center", gap: 5, padding: "4px 10px", borderRadius: 6, border: "1px solid #fecaca", background: "#fef2f2", color: "#dc2626", fontSize: 11, fontWeight: 700 }}>
      Missing
    </span>
  );
}

function Select({ value, onChange, options, placeholder, minWidth = 140 }: { value: string; onChange: (v: string) => void; options: { value: string; label: string }[]; placeholder: string; minWidth?: number }) {
  const active = !!value;
  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}
      style={{ appearance: "none", WebkitAppearance: "none", MozAppearance: "none", backgroundColor: active ? "#f0fdfa" : "#fff", backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>")`, backgroundRepeat: "no-repeat", backgroundPosition: "right 9px center", backgroundSize: "12px 12px", border: `1px solid ${active ? "#0f766e" : "#e2e8f0"}`, borderRadius: 8, padding: "8px 30px 8px 11px", fontSize: 12.5, fontWeight: 600, color: active ? "#0f766e" : "#374151", cursor: "pointer", minWidth, height: 38, outline: "none" }}>
      <option value="">{placeholder}</option>
      {options.map((o) => (<option key={o.value} value={o.value}>{o.label}</option>))}
    </select>
  );
}
