const { useEffect, useMemo, useRef, useState } = React;

const COMPANY_TIME_ZONE = "Asia/Kolkata";
function dateParts(value = new Date()) {
  return Object.fromEntries(new Intl.DateTimeFormat("en-GB", {
    timeZone: COMPANY_TIME_ZONE,
    year: "numeric",
    month: "2-digit",
    day: "2-digit"
  }).formatToParts(new Date(value)).filter((part) => part.type !== "literal").map((part) => [part.type, part.value]));
}
const today = () => {
  const parts = dateParts();
  return `${parts.year}-${parts.month}-${parts.day}`;
};
const thisMonth = () => today().slice(0, 7);
const money = (n) => `Rs. ${Number(n || 0).toLocaleString("en-IN", { maximumFractionDigits: 2 })}`;
const shortDate = (d) => (d ? new Date(d).toLocaleDateString("en-IN", { timeZone: COMPANY_TIME_ZONE }) : "-");
const timeOnly = (d) => (d ? new Date(d).toLocaleTimeString("en-IN", { timeZone: COMPANY_TIME_ZONE, hour: "2-digit", minute: "2-digit" }) : "-");
const compact = (value, fallback = "-") => (value === undefined || value === null || value === "" ? fallback : value);
const APP_BASE_PATH = (window.STAFF_MANAGER_BASE_PATH || "").replace(/\/$/, "");
const appPath = (path) => `${APP_BASE_PATH}${path.startsWith("/") ? path : `/${path}`}`;
const LOGO_SRC = appPath("/assets/the-flyers-bay-logo.png");
const screenLabels = {
  dashboard: "Command Center",
  employees: "People Directory",
  attendance: "Attendance Control",
  leaves: "Leave Desk",
  holidays: "Holiday Calendar",
  advances: "Salary Advances",
  payroll: "Payroll Run",
  reports: "Reports",
  settings: "Rules & Settings",
  punch: "Mobile Punch"
};

function cx(...classes) {
  return classes.filter(Boolean).join(" ");
}

function readFileAsDataUrl(file) {
  return new Promise((resolve) => {
    if (!file) return resolve("");
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.readAsDataURL(file);
  });
}

async function readDocumentFile(file) {
  if (!file) return null;
  return {
    fileName: file.name,
    mimeType: file.type || "application/octet-stream",
    dataUrl: await readFileAsDataUrl(file),
    uploadedAt: new Date().toISOString()
  };
}

function openDocument(doc) {
  if (!doc?.dataUrl) return;
  const win = window.open();
  if (!win) return;
  win.document.write(`<iframe src="${doc.dataUrl}" title="${doc.fileName || "document"}" style="border:0;height:100vh;width:100vw"></iframe>`);
}

function downloadCsv(rows, filename) {
  if (!rows?.length) return;
  const keys = Object.keys(rows[0]).filter((k) => typeof rows[0][k] !== "object");
  const csv = [keys.join(","), ...rows.map((row) => keys.map((key) => `"${String(row[key] ?? "").replaceAll('"', '""')}"`).join(","))].join("\n");
  const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename.endsWith(".csv") ? filename : `${filename}.csv`;
  a.click();
  URL.revokeObjectURL(url);
}

function exportPdf(title, rows) {
  if (!window.jspdf || !rows?.length) return;
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF({ orientation: "landscape" });
  const keys = Object.keys(rows[0]).filter((k) => typeof rows[0][k] !== "object").slice(0, 10);
  doc.text(title, 14, 14);
  doc.autoTable({
    startY: 20,
    head: [keys],
    body: rows.map((row) => keys.map((key) => String(row[key] ?? ""))),
    styles: { fontSize: 8 }
  });
  doc.save(`${title.replace(/\s+/g, "-").toLowerCase()}.pdf`);
}

function createSalarySlip(row) {
  if (!window.jspdf) return;
  const { jsPDF } = window.jspdf;
  const doc = new jsPDF();
  const m = (value) => money(value).replace("Rs.", "Rs. ");
  const text = (value) => compact(value, "-");
  const gross = Number(row.grossEarnings ?? (Number(row.baseSalary || 0) + Number(row.overtimeAmount || 0) + Number(row.bonus || 0)));
  const payrollDeductions = Number(row.totalDeductions ?? (Number(row.advanceDeduction || 0) + Number(row.unpaidLeaveDeduction || 0) + Number(row.otherDeductions || 0)));
  const ymd = new Date().toLocaleDateString("en-IN");

  doc.setFillColor(20, 20, 20);
  doc.rect(0, 0, 210, 30, "F");
  doc.setTextColor(248, 196, 0);
  doc.setFontSize(18);
  doc.setFont(undefined, "bold");
  doc.text("The Flyer's Bay", 14, 13);
  doc.setTextColor(255, 255, 255);
  doc.setFontSize(10);
  doc.text("Professional Salary Slip", 14, 22);
  doc.setFontSize(11);
  doc.text(`Month: ${text(row.month)}`, 150, 13);
  doc.text(`Generated: ${ymd}`, 150, 22);
  doc.setTextColor(20, 20, 20);

  doc.autoTable({
    startY: 38,
    theme: "grid",
    head: [["Employee Details", ""]],
    body: [
      ["Employee", text(row.employeeName)],
      ["Employee ID", text(row.kredilyEmployeeId || row.employeeCode)],
      ["Department / Designation", `${text(row.department)} / ${text(row.designation)}`],
      ["PAN / UAN / ESIC", `${text(row.panNumber)} / ${text(row.uanNumber)} / ${text(row.esicNumber)}`]
    ],
    styles: { fontSize: 9, cellPadding: 2 },
    headStyles: { fillColor: [248, 196, 0], textColor: [20, 20, 20] },
    columnStyles: { 0: { fontStyle: "bold", cellWidth: 55 }, 1: { cellWidth: 135 } }
  });

  const topY = doc.lastAutoTable.finalY + 6;
  doc.autoTable({
    startY: topY,
    theme: "grid",
    head: [["Attendance", "Value"]],
    body: [
      ["Required days", text(row.requiredWorkingDays)],
      ["Required hours", text(row.requiredWorkingHours)],
      ["Worked hours", text(row.actualWorkedHours)],
      ["Paid leave hours", text(row.paidLeaveHours)],
      ["Unpaid leave hours", text(row.unpaidLeaveHours)],
      ["Overtime hours", text(row.overtimeHours)]
    ],
    styles: { fontSize: 9, cellPadding: 2 },
    headStyles: { fillColor: [36, 45, 57] },
    margin: { right: 108 },
    tableWidth: 88
  });
  doc.autoTable({
    startY: topY,
    theme: "grid",
    head: [["Earnings", "Amount"]],
    body: [
      ["Monthly salary", m(row.monthlySalary)],
      ["Base payable", m(row.baseSalary)],
      ["Overtime", m(row.overtimeAmount)],
      ["Bonus", m(row.bonus)],
      ["Gross earnings", m(gross)]
    ],
    styles: { fontSize: 9, cellPadding: 2 },
    headStyles: { fillColor: [36, 45, 57] },
    margin: { left: 108 },
    tableWidth: 88
  });

  const midY = Math.max(doc.lastAutoTable.finalY, topY + 48) + 6;
  doc.autoTable({
    startY: midY,
    theme: "grid",
    head: [["Employee Deductions", "Amount"]],
    body: [
      ["Advance deduction", m(row.advanceDeduction)],
      ["Other deduction", m(row.otherDeductions)],
      ["PF employee deduction", m(row.pfEmployeeDeduction || 0)],
      ["ESI employee deduction", m(row.esiEmployeeDeduction || 0)],
      ["Total salary deduction", m(payrollDeductions)]
    ],
    styles: { fontSize: 9, cellPadding: 2 },
    headStyles: { fillColor: [36, 45, 57] },
    margin: { right: 108 },
    tableWidth: 88
  });
  doc.autoTable({
    startY: midY,
    theme: "grid",
    head: [["PF / ESI Paid By Company", "Amount"]],
    body: [
      ["PF employee share paid by company", m(row.pfEmployeeSharePaidByCompany)],
      ["PF employer EPF share", m(row.pfEmployerEpfContribution)],
      ["PF employer EPS share", m(row.pfEmployerEpsContribution)],
      ["ESI employee share paid by company", m(row.esiEmployeeSharePaidByCompany)],
      ["ESI employer share", m(row.esiEmployerContribution)],
      ["Total govt contribution", m(row.statutoryEmployerCost)]
    ],
    styles: { fontSize: 9, cellPadding: 2 },
    headStyles: { fillColor: [248, 196, 0], textColor: [20, 20, 20] },
    margin: { left: 108 },
    tableWidth: 88
  });

  const summaryY = doc.lastAutoTable.finalY + 8;
  doc.setFillColor(245, 247, 250);
  doc.roundedRect(14, summaryY, 182, 25, 2, 2, "F");
  doc.setFontSize(10);
  doc.setFont(undefined, "bold");
  doc.text("Net Salary Payable", 20, summaryY + 9);
  doc.setFontSize(16);
  doc.text(m(row.finalSalary), 20, summaryY + 19);
  doc.setFontSize(9);
  doc.setFont(undefined, "normal");
  doc.text("PF/ESI is paid separately by the company and is not deducted from employee salary.", 84, summaryY + 10);
  doc.text(`Total company cost including PF/ESI: ${m(row.totalCompanyCost)}`, 84, summaryY + 18);

  const notes = (row.steps || []).slice(-5).map((step, index) => [`${index + 1}`, step]);
  if (notes.length) {
    doc.autoTable({
      startY: summaryY + 33,
      theme: "plain",
      head: [["Calculation Notes", ""]],
      body: notes,
      styles: { fontSize: 8, cellPadding: 1.5 },
      headStyles: { textColor: [20, 20, 20], fontStyle: "bold" },
      columnStyles: { 0: { cellWidth: 8 }, 1: { cellWidth: 176 } }
    });
  }
  doc.setFontSize(8);
  doc.text("This is a system generated salary slip.", 14, 287);
  doc.save(`salary-slip-${row.employeeName}-${row.month}.pdf`);
}

function useApi(token, onUnauthorized) {
  return useMemo(() => {
    async function request(path, options = {}) {
      const res = await fetch(appPath(path), {
        ...options,
        headers: {
          "Content-Type": "application/json",
          ...(token ? { Authorization: `Bearer ${token}` } : {}),
          ...(options.headers || {})
        }
      });
      const data = await res.json().catch(() => ({}));
      if (res.status === 401 && onUnauthorized) onUnauthorized();
      if (!res.ok) {
        const error = new Error(data.error || "Request failed");
        error.status = res.status;
        error.data = data;
        throw error;
      }
      return data;
    }
    return {
      get: (path) => request(path),
      post: (path, body) => request(path, { method: "POST", body: JSON.stringify(body || {}) }),
      put: (path, body) => request(path, { method: "PUT", body: JSON.stringify(body || {}) }),
      del: (path) => request(path, { method: "DELETE" })
    };
  }, [token]);
}

function Field({ label, children }) {
  return (
    <label className="block">
      <span className="mb-1.5 block text-[11px] font-bold uppercase tracking-wide text-slate-500">{label}</span>
      {children}
    </label>
  );
}

function Input(props) {
  return <input {...props} className={cx("w-full rounded-md border border-line bg-white px-3 py-2.5 text-sm outline-none transition placeholder:text-slate-400 focus:border-brandDeep focus:ring-2 focus:ring-brand/30", props.className)} />;
}

function Select(props) {
  return <select {...props} className={cx("w-full rounded-md border border-line bg-white px-3 py-2.5 text-sm outline-none transition focus:border-brandDeep focus:ring-2 focus:ring-brand/30", props.className)} />;
}

function Button({ children, tone = "primary", className, ...props }) {
  const tones = {
    primary: "bg-brand text-charcoal shadow-sm hover:bg-brandDeep",
    secondary: "bg-white text-ink border border-line hover:border-brandDeep hover:bg-brand/10",
    dark: "bg-charcoal text-white hover:bg-night",
    danger: "bg-coral text-white hover:bg-coral/90",
    steel: "bg-steel text-white hover:bg-steel/90",
    ghost: "bg-transparent text-slate-700 hover:bg-black/5"
  };
  return (
    <button {...props} className={cx("inline-flex min-h-10 items-center justify-center rounded-md px-4 py-2 text-sm font-bold transition disabled:cursor-not-allowed disabled:opacity-50", tones[tone], className)}>
      {children}
    </button>
  );
}

function Card({ children, className }) {
  return <section className={cx("min-w-0 rounded-lg border border-line bg-white p-4 shadow-soft", className)}>{children}</section>;
}

function BrandMark({ compact = false, className = "" }) {
  return (
    <div className={cx("overflow-hidden rounded-lg border border-brandDeep/30 bg-brand shadow-sm", compact ? "h-12 w-12" : "h-16 w-28", className)}>
      <img src={LOGO_SRC} alt="The Flyer's Bay" className="h-full w-full object-cover" />
    </div>
  );
}

function BrandLockup({ compact = false }) {
  return (
    <div className="flex min-w-0 items-center gap-3">
      <BrandMark compact={compact} />
      <div className="min-w-0">
        <p className="truncate text-sm font-extrabold leading-tight text-ink">The Flyer's Bay</p>
        <p className="truncate text-[11px] font-bold uppercase tracking-wide text-slate-500">Staff Manager</p>
      </div>
    </div>
  );
}

function SectionTitle({ eyebrow, title, action }) {
  return (
    <div className="mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
      <div>
        {eyebrow && <p className="text-[11px] font-bold uppercase tracking-wide text-brandDeep">{eyebrow}</p>}
        <h2 className="text-lg font-extrabold text-ink">{title}</h2>
      </div>
      {action}
    </div>
  );
}

function StatusPill({ value }) {
  const color = {
    active: "bg-emerald-50 text-emerald-700 ring-emerald-200",
    inactive: "bg-slate-100 text-slate-700 ring-slate-200",
    approved: "bg-emerald-50 text-emerald-700 ring-emerald-200",
    rejected: "bg-rose-50 text-rose-700 ring-rose-200",
    pending: "bg-amber-50 text-amber-800 ring-amber-200",
    requested: "bg-amber-50 text-amber-800 ring-amber-200",
    present: "bg-emerald-50 text-emerald-700 ring-emerald-200",
    absent: "bg-rose-50 text-rose-700 ring-rose-200",
    half_day: "bg-amber-50 text-amber-800 ring-amber-200",
    open: "bg-amber-50 text-amber-800 ring-amber-200",
    deducted: "bg-slate-100 text-slate-700 ring-slate-200",
    paid: "bg-emerald-50 text-emerald-700 ring-emerald-200",
    unpaid: "bg-amber-50 text-amber-800 ring-amber-200",
    complete: "bg-emerald-50 text-emerald-700 ring-emerald-200"
  }[value] || "bg-slate-100 text-slate-700 ring-slate-200";
  return <span className={cx("inline-flex rounded-full px-2.5 py-1 text-xs font-bold capitalize ring-1", color)}>{String(value || "-").replaceAll("_", " ")}</span>;
}

function DataTable({ columns, rows, empty = "No records found" }) {
  return (
    <div className="max-w-full overflow-x-auto rounded-md border border-line">
      <table className="min-w-full text-left text-sm">
        <thead className="border-b border-line bg-slate-50 text-[11px] uppercase tracking-wide text-slate-500">
          <tr>{columns.map((col) => <th key={col.key} className="whitespace-nowrap px-3 py-3 font-extrabold">{col.label}</th>)}</tr>
        </thead>
        <tbody className="divide-y divide-line bg-white">
          {!rows?.length && (
            <tr><td className="px-3 py-8 text-center text-slate-500" colSpan={columns.length}>{empty}</td></tr>
          )}
          {rows?.map((row, idx) => (
            <tr key={row.id || idx} className="align-top transition hover:bg-brand/5">
              {columns.map((col) => <td key={col.key} className="whitespace-nowrap px-3 py-3">{col.render ? col.render(row) : compact(row[col.key])}</td>)}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

function Toast({ toast, onClose }) {
  if (!toast) return null;
  return (
    <div className="fixed bottom-4 left-4 right-4 z-50 mx-auto max-w-lg rounded-lg bg-charcoal px-4 py-3 text-sm text-white shadow-lift">
      <div className="flex items-start justify-between gap-3">
        <span>{toast}</span>
        <button className="font-semibold" onClick={onClose}>Close</button>
      </div>
    </div>
  );
}

function Login({ onLogin }) {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState("");

  async function submit(e) {
    e.preventDefault();
    setBusy(true);
    setError("");
    try {
      const res = await fetch(appPath("/api/auth/login"), {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ email, password })
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || "Login failed");
      onLogin(data.token, data.user);
    } catch (err) {
      setError(err.message);
    } finally {
      setBusy(false);
    }
  }

  return (
    <main className="min-h-screen bg-[linear-gradient(135deg,#f7f6f0,#fff8cf_44%,#f7f6f0)] p-4 lg:p-8">
      <div className="mx-auto grid min-h-[calc(100vh-2rem)] max-w-6xl overflow-hidden rounded-xl border border-line bg-white shadow-lift lg:grid-cols-[1.05fr_.95fr]">
        <section className="relative flex flex-col justify-between bg-charcoal p-6 text-white lg:p-10">
          <div className="absolute inset-x-0 top-0 h-1.5 bg-brand" />
          <div>
            <div className="inline-flex rounded-xl bg-brand p-1 shadow-soft">
              <img src={LOGO_SRC} alt="The Flyer's Bay" className="h-28 w-48 rounded-lg object-cover sm:h-32 sm:w-56" />
            </div>
            <div className="mt-8 max-w-lg">
              <p className="text-xs font-extrabold uppercase tracking-[0.2em] text-brand">HRMS Operations</p>
              <h1 className="mt-3 text-3xl font-extrabold leading-tight sm:text-4xl">The Flyer's Bay Staff Manager</h1>
              <p className="mt-4 text-sm leading-6 text-white/70">Attendance, leave, payroll, salary advances, and field punch records in one controlled workspace.</p>
            </div>
          </div>
          <div className="mt-8 grid gap-3 text-sm sm:grid-cols-3">
            {["GPS Punch", "Payroll Ready", "Leave Desk"].map((item) => (
              <div key={item} className="rounded-lg border border-white/10 bg-white/5 p-3">
                <p className="font-bold text-brand">{item}</p>
                <p className="mt-1 text-xs text-white/60">Live workflow</p>
              </div>
            ))}
          </div>
        </section>
        <section className="flex items-center justify-center p-5 sm:p-8">
          <Card className="w-full max-w-md border-0 p-0 shadow-none">
            <div className="mb-6">
              <BrandLockup compact />
              <h2 className="mt-6 text-2xl font-extrabold">Sign in</h2>
              <p className="mt-2 text-sm text-slate-600">Use your admin or employee account.</p>
            </div>
        <form className="space-y-4" onSubmit={submit}>
          <Field label="Email"><Input value={email} onChange={(e) => setEmail(e.target.value)} /></Field>
          <Field label="Password"><Input type="password" value={password} onChange={(e) => setPassword(e.target.value)} /></Field>
          {error && <p className="rounded-md bg-rose-50 p-3 text-sm text-rose-700">{error}</p>}
          <Button className="w-full" disabled={busy}>{busy ? "Signing in..." : "Sign in"}</Button>
        </form>
      </Card>
        </section>
      </div>
    </main>
  );
}

function Shell({ user, screen, setScreen, logout, children }) {
  const [open, setOpen] = useState(false);
  const adminNav = [
    ["dashboard", "Dashboard", "Ops"],
    ["employees", "Employees", "People"],
    ["attendance", "Attendance", "Time"],
    ["leaves", "Leaves", "Desk"],
    ["holidays", "Holidays", "Cal"],
    ["advances", "Advances", "Pay"],
    ["payroll", "Payroll", "Run"],
    ["reports", "Reports", "Data"],
    ["settings", "Settings", "Rules"]
  ];
  const employeeNav = [
    ["punch", "Punch", "Now"],
    ["attendance", "My Attendance", "Time"],
    ["leaves", "My Leaves", "Desk"],
    ["payroll", "Salary Slip", "Pay"],
    ["advances", "My Advances", "Pay"],
    ["holidays", "Holidays", "Cal"]
  ];
  const nav = user.role === "admin" ? adminNav : employeeNav;
  const employeeTitles = { attendance: "My Attendance", leaves: "My Leaves", payroll: "Salary Slip", advances: "My Advances", holidays: "Holidays", punch: "Mobile Punch" };
  const NavButton = ({ item }) => (
    <button
      aria-label={`${item[2]} ${item[1]}`}
      className={cx(
        "group flex w-full items-center gap-3 rounded-md px-3 py-2.5 text-left text-sm font-bold transition",
        screen === item[0] ? "bg-charcoal text-white shadow-sm" : "text-slate-700 hover:bg-brand/10 hover:text-ink"
      )}
      onClick={() => {
        setScreen(item[0]);
        setOpen(false);
      }}
    >
      <span className={cx("grid h-8 w-8 shrink-0 place-items-center rounded-md text-[11px] font-extrabold", screen === item[0] ? "bg-brand text-charcoal" : "bg-slate-100 text-slate-500 group-hover:bg-brand group-hover:text-charcoal")}>{item[2]}</span>
      <span>{item[1]}</span>
    </button>
  );
  const title = (user.role === "employee" && employeeTitles[screen]) || screenLabels[screen] || screen.replaceAll("_", " ");

  return (
    <div className="min-h-screen bg-paper lg:flex">
      <aside className={cx("fixed inset-y-0 left-0 z-40 flex w-72 transform flex-col border-r border-line bg-white p-4 transition lg:static lg:translate-x-0", open ? "translate-x-0" : "-translate-x-full")}>
        <div className="mb-5">
          <BrandLockup />
        </div>
        <div className="mb-5 rounded-lg bg-charcoal p-3 text-white">
          <p className="truncate text-sm font-extrabold">{user.name}</p>
          <div className="mt-1 flex items-center justify-between gap-2 text-xs text-white/60">
            <span className="truncate capitalize">{user.role}</span>
            <span>{today()}</span>
          </div>
        </div>
        <nav className="grid gap-1">{nav.map((item) => <NavButton key={item[0]} item={item} />)}</nav>
        <div className="mt-auto pt-5">
          <Button tone="secondary" className="w-full" onClick={logout}>Logout</Button>
        </div>
      </aside>
      {open && <button className="fixed inset-0 z-30 bg-black/30 lg:hidden" onClick={() => setOpen(false)} />}
      <div className="flex min-w-0 flex-1 flex-col">
        <header className="sticky top-0 z-20 flex items-center justify-between gap-3 border-b border-line bg-paper/95 px-4 py-3 backdrop-blur">
          <button className="rounded-md border border-line bg-white px-3 py-2 text-sm font-bold lg:hidden" onClick={() => setOpen(true)}>Menu</button>
          <div className="min-w-0">
            <p className="text-[11px] font-extrabold uppercase tracking-wide text-brandDeep">The Flyer's Bay HRMS</p>
            <h1 className="truncate text-lg font-extrabold capitalize">{title}</h1>
          </div>
          <div className="hidden min-w-0 text-right text-sm sm:block">
            <p className="truncate font-bold">{user.email}</p>
            <p className="text-slate-500">{today()}</p>
          </div>
        </header>
        <main className="p-4 lg:p-6 xl:p-8">{children}</main>
      </div>
    </div>
  );
}

function Dashboard({ api, setScreen, setAttendanceFilterPreset }) {
  const [data, setData] = useState(null);
  useEffect(() => { api.get("/api/dashboard").then(setData); }, []);
  if (!data) return <p>Loading dashboard...</p>;
  const todayMetrics = [
    ["Present", data.presentToday, "text-emerald-300", { status: "present", issue: "all" }],
    ["Absent", data.absentToday, "text-rose-300", { status: "absent", issue: "all" }],
    ["Late", data.lateToday, "text-amber-300", { status: "all", issue: "late" }]
  ];
  const actionQueue = [
    ["Leaves waiting", data.pendingLeaves, "leaves"],
    ["Advance balances", data.pendingAdvances, "advances"],
    ["Attendance alerts", data.suspiciousAttempts, "attendance"]
  ];
  const overviewCards = [
    ["People directory", data.totalEmployees, "employees", "bg-charcoal text-white"],
    ["Payroll payable", money(data.monthlySalaryPayable), "payroll", "bg-brand text-charcoal"],
    ["Holiday calendar", data.upcomingHolidays.length, "holidays", "bg-blue-50 text-blue-700"],
    ["Reports center", "Open", "reports", "bg-slate-100 text-slate-700"]
  ];
  const go = (target) => {
    if (setScreen) setScreen(target);
  };
  const goAttendance = (preset) => {
    if (setAttendanceFilterPreset) setAttendanceFilterPreset({ employeeId: "", status: preset.status, issue: preset.issue, date: today(), search: "" });
    go("attendance");
  };
  return (
    <div className="grid gap-4">
      <div className="grid gap-4 xl:grid-cols-[1.45fr_.85fr]">
        <section className="rounded-xl bg-charcoal p-5 text-white shadow-lift">
          <div className="flex flex-col justify-between gap-5 sm:flex-row sm:items-start">
            <div>
              <p className="text-xs font-extrabold uppercase tracking-[0.2em] text-brand">Today</p>
              <h2 className="mt-2 text-2xl font-extrabold">Attendance command center</h2>
              <p className="mt-2 max-w-xl text-sm leading-6 text-white/65">Review presence, exceptions, and payroll readiness before closing the day.</p>
            </div>
            <div className="rounded-lg bg-brand px-4 py-3 text-charcoal">
              <p className="text-[11px] font-extrabold uppercase tracking-wide">Monthly payable</p>
              <p className="mt-1 text-xl font-extrabold">{money(data.monthlySalaryPayable)}</p>
            </div>
          </div>
          <div className="mt-5 grid gap-3 sm:grid-cols-3">
            {todayMetrics.map(([label, value, color, preset]) => (
              <button key={label} type="button" onClick={() => goAttendance(preset)} className="rounded-lg border border-white/10 bg-white/5 p-4 text-left transition hover:border-brand hover:bg-white/10">
                <p className="text-xs font-bold uppercase tracking-wide text-white/50">{label}</p>
                <p className={cx("mt-2 text-3xl font-extrabold", color)}>{value}</p>
              </button>
            ))}
          </div>
        </section>
        <Card>
          <SectionTitle eyebrow="Action queue" title="Needs review" />
          <div className="grid gap-3">
            {actionQueue.map(([label, value, target]) => (
              <button key={label} type="button" onClick={() => go(target)} className="flex items-center justify-between rounded-lg border border-line bg-paper px-3 py-3 text-left transition hover:border-brandDeep hover:bg-brand/10">
                <span className="text-sm font-bold text-slate-700">{label}</span>
                <span className="grid h-9 min-w-9 place-items-center rounded-md bg-charcoal px-2 text-sm font-extrabold text-brand">{value}</span>
              </button>
            ))}
          </div>
        </Card>
      </div>
      <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
        {overviewCards.map(([label, value, target, tone]) => (
          <button key={label} type="button" onClick={() => go(target)} className="rounded-lg border border-line bg-white p-0 text-left shadow-soft transition hover:border-brandDeep hover:shadow-lift">
            <div className="p-4">
              <div className={cx("inline-flex rounded-md px-2.5 py-1 text-[11px] font-extrabold uppercase tracking-wide", tone)}>{label}</div>
              <p className="mt-3 text-2xl font-extrabold">{value}</p>
            </div>
          </button>
        ))}
      </div>
      <Card>
        <SectionTitle eyebrow="Calendar" title="Next holidays" action={<Button tone="secondary" onClick={() => go("holidays")}>Open holidays</Button>} />
        <DataTable columns={[
          { key: "date", label: "Date" },
          { key: "name", label: "Name" },
          { key: "type", label: "Type" },
          { key: "paid", label: "Paid", render: (r) => r.paid ? "Yes" : "No" }
        ]} rows={data.upcomingHolidays} />
      </Card>
    </div>
  );
}

function Employees({ api, toast }) {
  const blankDocuments = { aadhaar: null, pan: null, photo: null };
  const blank = { name: "", phone: "", alternatePhone: "", email: "", address: "", currentAddress: "", permanentAddress: "", designation: "", department: "", employeeType: "", workLocation: "", joiningDate: today(), dateOfBirth: "", gender: "", panNumber: "", pfEnabled: true, pfNumber: "", uanNumber: "", esiEnabled: true, esicNumber: "", monthlySalary: "", overtimeRate: "", status: "active", profilePhoto: "", documents: blankDocuments, password: "", kredilyEmployeeId: "" };
  const [employees, setEmployees] = useState([]);
  const [form, setForm] = useState(blank);
  const [editing, setEditing] = useState(null);
  const [formOpen, setFormOpen] = useState(false);
  const [filters, setFilters] = useState({ search: "", status: "all", department: "all", missing: "all" });

  async function load() {
    setEmployees(await api.get("/api/employees"));
  }
  useEffect(() => { load(); }, []);

  async function save(e) {
    e.preventDefault();
    if (editing && form.status === "inactive" && !window.confirm(`Mark ${form.name || "this employee"} inactive? Their login will be disabled.`)) return;
    if (editing) await api.put(`/api/employees/${editing}`, form);
    else await api.post("/api/employees", form);
    setForm(blank);
    setEditing(null);
    setFormOpen(false);
    await load();
    toast("Employee saved");
  }

  async function remove(row) {
    if (!window.confirm(`Mark ${row.name} inactive? Their login will be disabled.`)) return;
    await api.del(`/api/employees/${row.id}?confirm=true`);
    await load();
    toast("Employee marked inactive");
  }

  async function photo(file) {
    setForm({ ...form, profilePhoto: await readFileAsDataUrl(file) });
  }

  async function documentFile(type, file) {
    const doc = await readDocumentFile(file);
    if (!doc) return;
    setForm({ ...form, documents: { ...blankDocuments, ...(form.documents || {}), [type]: doc } });
  }

  function edit(row) {
    setEditing(row.id);
    setForm({ ...blank, ...row, documents: { ...blankDocuments, ...(row.documents || {}) }, password: "" });
    setFormOpen(true);
  }

  function openCreate() {
    setEditing(null);
    setForm(blank);
    setFormOpen(true);
  }

  function closeForm() {
    setEditing(null);
    setForm(blank);
    setFormOpen(false);
  }

  function docButtons(row) {
    const docs = row.documents || {};
    const items = [
      ["aadhaar", "Aadhaar"],
      ["pan", "PAN"],
      ["photo", "Photo"]
    ].filter(([key]) => docs[key]?.dataUrl);
    if (!items.length) return "-";
    return (
      <div className="flex flex-wrap gap-1.5">
        {items.map(([key, label]) => <Button key={key} type="button" tone="secondary" className="min-h-8 px-2 py-1 text-xs" onClick={() => openDocument(docs[key])}>{label}</Button>)}
      </div>
    );
  }
  const hasDocument = (row, key) => Boolean(row.documents?.[key]?.dataUrl);
  const fieldChecks = [
    ["kredilyEmployeeId", "Employee ID", (row) => row.kredilyEmployeeId],
    ["department", "Department", (row) => row.department],
    ["employeeType", "Type", (row) => row.employeeType],
    ["phone", "Phone", (row) => row.phone],
    ["dateOfBirth", "DOB", (row) => row.dateOfBirth],
    ["gender", "Gender", (row) => row.gender],
    ["currentAddress", "Current address", (row) => row.currentAddress || row.address],
    ["permanentAddress", "Permanent address", (row) => row.permanentAddress],
    ["panNumber", "PAN", (row) => row.panNumber],
    ["uanNumber", "UAN", (row) => row.pfEnabled === false || row.uanNumber || row.pfNumber],
    ["esicNumber", "ESIC IP", (row) => row.esiEnabled === false || row.esicNumber],
    ["aadhaarDocument", "Aadhaar doc", (row) => hasDocument(row, "aadhaar") || hasDocument(row, "aadhar")],
    ["panDocument", "PAN doc", (row) => hasDocument(row, "pan")],
    ["photoDocument", "Photo doc", (row) => hasDocument(row, "photo")],
    ["profilePhoto", "Punch photo", (row) => row.profilePhoto]
  ];
  const missingFields = (row) => fieldChecks.filter(([, , getter]) => !getter(row)).map(([, label]) => label);
  const departments = [...new Set(employees.map((employee) => employee.department).filter(Boolean))].sort();
  const filteredEmployees = employees.filter((employee) => {
    const search = filters.search.trim().toLowerCase();
    const haystack = [
      employee.name,
      employee.kredilyEmployeeId,
      employee.department,
      employee.designation,
      employee.employeeType,
      employee.workLocation,
      employee.phone,
      employee.email,
      employee.panNumber,
      employee.uanNumber,
      employee.esicNumber
    ].join(" ").toLowerCase();
    if (search && !haystack.includes(search)) return false;
    if (filters.status !== "all" && employee.status !== filters.status) return false;
    if (filters.department !== "all" && employee.department !== filters.department) return false;
    if (filters.missing !== "all") {
      const check = fieldChecks.find(([key]) => key === filters.missing);
      if (!check || check[2](employee)) return false;
    }
    return true;
  });
  const missingCount = (key) => {
    const check = fieldChecks.find(([field]) => field === key);
    return check ? employees.filter((employee) => !check[2](employee)).length : 0;
  };
  const healthCards = [
    ["Active", employees.filter((employee) => employee.status === "active").length],
    ["Inactive", employees.filter((employee) => employee.status !== "active").length],
    ["Missing PAN", missingCount("panNumber")],
    ["Missing UAN", missingCount("uanNumber")],
    ["Missing DOB", missingCount("dateOfBirth")],
    ["Missing address", missingCount("currentAddress")],
    ["Missing docs", missingCount("aadhaarDocument") + missingCount("panDocument")]
  ];
  const resetEmployeeFilters = () => setFilters({ search: "", status: "all", department: "all", missing: "all" });

  const employeeForm = (
        <form className="grid gap-3" onSubmit={save}>
          <Field label="Name"><Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} required /></Field>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Employee ID"><Input value={form.kredilyEmployeeId || ""} onChange={(e) => setForm({ ...form, kredilyEmployeeId: e.target.value })} /></Field>
            <Field label="Status"><Select value={form.status} onChange={(e) => setForm({ ...form, status: e.target.value })}><option>active</option><option>inactive</option></Select></Field>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Phone"><Input value={form.phone} onChange={(e) => setForm({ ...form, phone: e.target.value })} /></Field>
            <Field label="Alternate phone"><Input value={form.alternatePhone || ""} onChange={(e) => setForm({ ...form, alternatePhone: e.target.value })} /></Field>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Email"><Input type="email" value={form.email} onChange={(e) => setForm({ ...form, email: e.target.value })} required /></Field>
            <Field label="Gender"><Select value={form.gender || ""} onChange={(e) => setForm({ ...form, gender: e.target.value })}><option value="">Select</option><option>Male</option><option>Female</option><option>Other</option></Select></Field>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Designation"><Input value={form.designation} onChange={(e) => setForm({ ...form, designation: e.target.value })} /></Field>
            <Field label="Department"><Input value={form.department || ""} onChange={(e) => setForm({ ...form, department: e.target.value })} /></Field>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Employee type"><Input value={form.employeeType || ""} onChange={(e) => setForm({ ...form, employeeType: e.target.value })} /></Field>
            <Field label="Work location"><Input value={form.workLocation || ""} onChange={(e) => setForm({ ...form, workLocation: e.target.value })} /></Field>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Joining date"><Input type="date" value={form.joiningDate} onChange={(e) => setForm({ ...form, joiningDate: e.target.value })} /></Field>
            <Field label="Date of birth"><Input type="date" value={form.dateOfBirth || ""} onChange={(e) => setForm({ ...form, dateOfBirth: e.target.value })} /></Field>
          </div>
          <Field label="Current address"><Input value={form.currentAddress || form.address || ""} onChange={(e) => setForm({ ...form, currentAddress: e.target.value, address: e.target.value })} /></Field>
          <Field label="Permanent address"><Input value={form.permanentAddress || ""} onChange={(e) => setForm({ ...form, permanentAddress: e.target.value })} /></Field>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="PAN number"><Input value={form.panNumber || ""} onChange={(e) => setForm({ ...form, panNumber: e.target.value.toUpperCase() })} /></Field>
            <Field label="Monthly salary"><Input type="number" value={form.monthlySalary} onChange={(e) => setForm({ ...form, monthlySalary: e.target.value })} /></Field>
          </div>
          <div className="rounded-md border border-line bg-slate-50 p-3">
            <p className="mb-3 text-[11px] font-bold uppercase tracking-wide text-slate-500">Statutory details</p>
            <div className="mb-3 grid gap-2 text-xs font-semibold text-amber-800">
              {form.pfEnabled !== false && !(form.uanNumber || form.pfNumber) && <p className="rounded-md border border-amber-200 bg-amber-50 px-3 py-2">PF is enabled. Add UAN or PF account number before payroll finalization.</p>}
              {form.esiEnabled !== false && !form.esicNumber && <p className="rounded-md border border-amber-200 bg-amber-50 px-3 py-2">ESI is enabled. Add ESIC IP number before payroll finalization.</p>}
              {!form.panNumber && <p className="rounded-md border border-amber-200 bg-amber-50 px-3 py-2">PAN number is missing.</p>}
            </div>
            <div className="grid gap-3 sm:grid-cols-2">
              <Field label="PF enabled"><Select value={String(form.pfEnabled !== false)} onChange={(e) => setForm({ ...form, pfEnabled: e.target.value === "true" })}><option value="true">Yes</option><option value="false">No</option></Select></Field>
              <Field label="ESI enabled"><Select value={String(form.esiEnabled !== false)} onChange={(e) => setForm({ ...form, esiEnabled: e.target.value === "true" })}><option value="true">Yes</option><option value="false">No</option></Select></Field>
              <Field label="PF account number"><Input value={form.pfNumber || ""} onChange={(e) => setForm({ ...form, pfNumber: e.target.value })} /></Field>
              <Field label="UAN number"><Input value={form.uanNumber || ""} onChange={(e) => setForm({ ...form, uanNumber: e.target.value })} /></Field>
              <Field label="ESIC IP number"><Input value={form.esicNumber || ""} onChange={(e) => setForm({ ...form, esicNumber: e.target.value })} /></Field>
            </div>
          </div>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Overtime rate"><Input type="number" value={form.overtimeRate} onChange={(e) => setForm({ ...form, overtimeRate: e.target.value })} /></Field>
            <Field label="Login password"><Input value={form.password || ""} required={!editing} placeholder={editing ? "Leave blank to keep old password" : ""} onChange={(e) => setForm({ ...form, password: e.target.value })} /></Field>
          </div>
          <Field label="Profile photo for photo match">
            <Input type="file" accept="image/*" onChange={(e) => photo(e.target.files[0])} />
          </Field>
          {form.profilePhoto && <img src={form.profilePhoto} className="h-24 w-24 rounded-md object-cover" />}
          <div className="grid gap-3 sm:grid-cols-3">
            <Field label="Aadhaar document"><Input type="file" accept="image/*,application/pdf" onChange={(e) => documentFile("aadhaar", e.target.files[0])} /></Field>
            <Field label="PAN document"><Input type="file" accept="image/*,application/pdf" onChange={(e) => documentFile("pan", e.target.files[0])} /></Field>
            <Field label="Employee photo document"><Input type="file" accept="image/*" onChange={(e) => documentFile("photo", e.target.files[0])} /></Field>
          </div>
          {Object.entries(form.documents || {}).some(([, doc]) => doc?.fileName) && (
            <div className="rounded-md border border-line bg-slate-50 p-3 text-xs text-slate-600">
              {Object.entries(form.documents || {}).filter(([, doc]) => doc?.fileName).map(([key, doc]) => (
                <div key={key} className="flex items-center justify-between gap-2 py-1">
                  <span className="font-semibold capitalize">{key}</span>
                  <button type="button" className="truncate text-brandDeep underline" onClick={() => openDocument(doc)}>{doc.fileName}</button>
                </div>
              ))}
            </div>
          )}
          <div className="flex gap-2">
            <Button>{editing ? "Update" : "Create"}</Button>
            <Button type="button" tone="secondary" onClick={closeForm}>Cancel</Button>
          </div>
        </form>
  );

  return (
    <div className="grid gap-4">
      {formOpen && (
        <div className="fixed inset-0 z-40 flex bg-charcoal/45 backdrop-blur-sm" role="dialog" aria-modal="true" aria-label={editing ? "Edit employee" : "Add employee"}>
          <button type="button" className="absolute inset-0 h-full w-full cursor-default" aria-label="Close employee form" onClick={closeForm} />
          <section className="relative ml-auto flex h-full w-full max-w-3xl flex-col bg-white shadow-lift">
            <div className="flex items-center justify-between gap-3 border-b border-line px-4 py-4">
              <div>
                <p className="text-[11px] font-bold uppercase tracking-wide text-brandDeep">People directory</p>
                <h2 className="text-lg font-extrabold text-ink">{editing ? "Edit employee" : "Add employee"}</h2>
              </div>
              <Button type="button" tone="secondary" onClick={closeForm} className="min-h-9 px-3">Close</Button>
            </div>
            <div className="min-h-0 flex-1 overflow-y-auto p-4">
              {employeeForm}
            </div>
          </section>
        </div>
      )}
      <Card>
        <div className="mb-4 flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
          <div>
            <h2 className="text-lg font-bold">Employees</h2>
            <p className="mt-1 text-sm text-slate-500">Directory, source fields, and missing data checks.</p>
          </div>
          <div className="flex flex-wrap justify-end gap-2">
            <Button onClick={openCreate}>Add employee</Button>
            <Button tone="secondary" onClick={() => downloadCsv(filteredEmployees, "employees.csv")}>Export CSV</Button>
          </div>
        </div>
        <div className="mb-4 grid gap-2 sm:grid-cols-3 xl:grid-cols-6">
          {healthCards.map(([label, value]) => (
            <div key={label} className="rounded-md border border-line bg-paper px-3 py-2">
              <p className="text-[11px] font-bold uppercase tracking-wide text-slate-500">{label}</p>
              <p className="mt-1 text-lg font-extrabold text-ink">{value}</p>
            </div>
          ))}
        </div>
        <div className="mb-4 grid gap-3 md:grid-cols-5 md:items-end">
          <Field label="Search"><Input value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} placeholder="Name, ID, phone, role" /></Field>
          <Field label="Status"><Select value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}><option value="all">All status</option><option value="active">Active</option><option value="inactive">Inactive</option></Select></Field>
          <Field label="Department"><Select value={filters.department} onChange={(e) => setFilters({ ...filters, department: e.target.value })}><option value="all">All departments</option>{departments.map((department) => <option key={department} value={department}>{department}</option>)}</Select></Field>
          <Field label="Missing data"><Select value={filters.missing} onChange={(e) => setFilters({ ...filters, missing: e.target.value })}><option value="all">All records</option>{fieldChecks.map(([key, label]) => <option key={key} value={key}>{label} missing</option>)}</Select></Field>
          <Button tone="secondary" onClick={resetEmployeeFilters}>Reset</Button>
        </div>
        <DataTable rows={filteredEmployees} columns={[
          { key: "kredilyEmployeeId", label: "ID", render: (r) => compact(r.kredilyEmployeeId || r.salaryAppEmployeeId) },
          { key: "name", label: "Name", render: (r) => <div className="flex items-center gap-2">{r.profilePhoto ? <img src={r.profilePhoto} className="h-8 w-8 rounded-full object-cover" /> : <span className="h-8 w-8 rounded-full bg-slate-100" />}<div><p className="font-semibold">{r.name}</p><p className="text-xs text-slate-500">{compact(r.employeeType)}</p></div></div> },
          { key: "department", label: "Dept / Role", render: (r) => <div><p className="font-semibold">{compact(r.department)}</p><p className="text-xs text-slate-500">{compact(r.designation)}</p></div> },
          { key: "contact", label: "Contact", render: (r) => <div><p>{compact(r.phone)}</p><p className="text-xs text-slate-500">{compact(r.email)}</p></div> },
          { key: "personal", label: "DOB / Gender", render: (r) => <div><p>{compact(r.dateOfBirth)}</p><p className="text-xs text-slate-500">{compact(r.gender)}</p></div> },
          { key: "panDocs", label: "PAN / PF / ESI", render: (r) => <div><p>{compact(r.panNumber)}</p><p className="text-xs text-slate-500">UAN {compact(r.uanNumber || r.pfNumber)}</p><p className="text-xs text-slate-500">ESIC {compact(r.esicNumber)}</p><div className="mt-1">{docButtons(r)}</div></div> },
          { key: "monthlySalary", label: "Salary", render: (r) => money(r.monthlySalary) },
          { key: "missing", label: "Missing info", render: (r) => {
            const missing = missingFields(r);
            if (!missing.length) return <StatusPill value="complete" />;
            return <div className="flex max-w-xs flex-wrap gap-1 whitespace-normal">{missing.slice(0, 4).map((item) => <span key={item} className="rounded-full bg-amber-50 px-2 py-1 text-xs font-bold text-amber-800 ring-1 ring-amber-200">{item}</span>)}{missing.length > 4 && <span className="rounded-full bg-slate-100 px-2 py-1 text-xs font-bold text-slate-600">+{missing.length - 4}</span>}</div>;
          } },
          { key: "status", label: "Status", render: (r) => <StatusPill value={r.status} /> },
          { key: "actions", label: "Actions", render: (r) => <div className="flex gap-2"><Button tone="secondary" onClick={() => edit(r)}>Edit</Button><Button tone="danger" onClick={() => remove(r)}>Inactive</Button></div> }
        ]} />
      </Card>
    </div>
  );
}

function SelfieCapture({ onCapture, onCancel, actionLabel = "Capture selfie" }) {
  const videoRef = useRef(null);
  const streamRef = useRef(null);
  const [active, setActive] = useState(false);
  const [error, setError] = useState("");

  async function start() {
    try {
      setError("");
      const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" } });
      streamRef.current = stream;
      if (videoRef.current) videoRef.current.srcObject = stream;
      setActive(true);
    } catch (err) {
      setError(err.message || "Camera permission was blocked");
    }
  }

  function capture() {
    const video = videoRef.current;
    const canvas = document.createElement("canvas");
    const sourceWidth = video.videoWidth || 480;
    const sourceHeight = video.videoHeight || 360;
    const scale = Math.min(1, 180 / sourceWidth);
    canvas.width = Math.round(sourceWidth * scale);
    canvas.height = Math.round(sourceHeight * scale);
    canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height);
    const dataUrl = canvas.toDataURL("image/jpeg", 0.55);
    stop();
    onCapture(dataUrl);
  }

  function stop() {
    streamRef.current?.getTracks().forEach((track) => track.stop());
    streamRef.current = null;
    setActive(false);
  }

  useEffect(() => {
    start();
    return stop;
  }, []);

  return (
    <div className="grid gap-3">
      <video ref={videoRef} autoPlay playsInline muted className={cx("aspect-video w-full rounded-lg bg-slate-100 object-cover", active ? "block" : "hidden")} />
      {!active && !error && <div className="flex aspect-video w-full items-center justify-center rounded-lg bg-slate-100 text-sm font-bold text-slate-500">Opening camera...</div>}
      {error && <p className="rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm font-semibold text-amber-800">{error}</p>}
      <div className="flex flex-wrap gap-2">
        <Button type="button" tone="steel" onClick={capture} disabled={!active}>{actionLabel}</Button>
        <Button type="button" tone="secondary" onClick={() => { stop(); onCancel?.(); }}>Cancel</Button>
      </div>
    </div>
  );
}

function attendanceLogs(row) {
  if (Array.isArray(row?.punchLogs) && row.punchLogs.length) return row.punchLogs;
  const logs = [];
  if (row?.punchIn) logs.push({ id: `${row.id}-in`, type: "in", time: row.punchIn, location: row.punchInLocation || null, selfie: row.punchInSelfie || "" });
  if (row?.punchOut) logs.push({ id: `${row.id}-out`, type: "out", time: row.punchOut, location: row.punchOutLocation || null, selfie: row.punchOutSelfie || "" });
  return logs;
}

function formatDuration(ms) {
  const safeMs = Math.max(0, Number(ms || 0));
  const totalSeconds = Math.floor(safeMs / 1000);
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const seconds = totalSeconds % 60;
  return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
}

function punchLogsDurationMs(logs, nowValue = new Date()) {
  let openIn = null;
  let total = 0;
  for (const log of logs || []) {
    const time = new Date(log.time);
    if (Number.isNaN(time.getTime())) continue;
    if (log.type === "in") {
      openIn = time;
      continue;
    }
    if (log.type === "out" && openIn) {
      total += Math.max(0, time - openIn);
      openIn = null;
    }
  }
  if (openIn) total += Math.max(0, new Date(nowValue) - openIn);
  return total;
}

function PunchLogList({ logs }) {
  if (!Array.isArray(logs) || !logs.length) return "-";
  return (
    <div className="flex max-w-sm flex-wrap gap-1 whitespace-normal">
      {logs.slice(-6).map((log) => (
        <span key={log.id || `${log.type}-${log.time}`} className={cx("rounded-full px-2 py-1 text-xs font-bold ring-1", log.type === "in" ? "bg-emerald-50 text-emerald-700 ring-emerald-200" : "bg-sky-50 text-sky-700 ring-sky-200")}>
          {log.type === "in" ? "In" : "Out"} {timeOnly(log.time)}
        </span>
      ))}
      {logs.length > 6 && <span className="rounded-full bg-slate-100 px-2 py-1 text-xs font-bold text-slate-600 ring-1 ring-slate-200">+{logs.length - 6}</span>}
    </div>
  );
}

function EvidenceCell({ row }) {
  const logs = attendanceLogs(row);
  if (!logs.length) return "-";
  const openSelfie = (log) => {
    if (!log.selfie) return;
    const win = window.open();
    if (!win) return;
    win.document.write(`<title>Punch selfie</title><body style="margin:0;background:#111;display:grid;place-items:center;min-height:100vh"><img src="${log.selfie}" style="max-width:96vw;max-height:96vh;image-rendering:auto" /></body>`);
  };
  const mapUrl = (location) => location?.latitude && location?.longitude ? `https://www.google.com/maps?q=${location.latitude},${location.longitude}` : "";
  return (
    <div className="grid min-w-44 gap-1 whitespace-normal">
      {logs.slice(-4).map((log) => {
        const url = mapUrl(log.location);
        return (
          <div key={log.id || `${log.type}-${log.time}`} className="flex items-center gap-2 rounded-md border border-line bg-paper p-1.5">
            <button type="button" className="h-9 w-9 shrink-0 overflow-hidden rounded border border-line bg-white" onClick={() => openSelfie(log)} disabled={!log.selfie} title={log.selfie ? "Open selfie" : "No selfie saved"}>
              {log.selfie ? <img src={log.selfie} alt="" className="h-full w-full object-cover" /> : <span className="block pt-2 text-center text-[10px] font-bold text-slate-400">No</span>}
            </button>
            <div className="min-w-0">
              <p className="text-xs font-extrabold">{log.type === "in" ? "In" : "Out"} {timeOnly(log.time)}</p>
              {url ? <a href={url} target="_blank" className="text-xs font-bold text-steel underline">GPS {Math.round(Number(log.location.distanceMeters || 0))}m</a> : <p className="text-xs font-bold text-slate-400">No GPS</p>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function AttendanceCardList({ rows }) {
  const sortedRows = [...(rows || [])].sort((a, b) => String(b.date || "").localeCompare(String(a.date || "")));
  if (!sortedRows.length) return <p className="rounded-md border border-line bg-paper px-3 py-6 text-center text-sm font-bold text-slate-500">No attendance records yet.</p>;
  return (
    <div className="grid gap-3">
      {sortedRows.map((row) => {
        const logs = attendanceLogs(row);
        const lastLog = logs.at(-1);
        const rowWorkingMs = row.date === today() ? punchLogsDurationMs(logs, lastLog?.type === "in" ? new Date() : (row.punchOut || new Date())) : Number(row.workedHours || 0) * 3600000;
        return (
          <article key={row.id || row.date} className="rounded-lg border border-line bg-white p-3 shadow-sm">
            <div className="flex items-start justify-between gap-3">
              <div className="min-w-0">
                <p className="text-xs font-extrabold uppercase tracking-wide text-brandDeep">{row.date === today() ? "Today" : shortDate(row.date)}</p>
                <p className="mt-1 text-lg font-extrabold text-ink">{row.date}</p>
              </div>
              <StatusPill value={row.status} />
            </div>
            <div className="mt-3 grid grid-cols-3 gap-2">
              <div className="rounded-md bg-paper px-3 py-2">
                <p className="text-[11px] font-extrabold uppercase tracking-wide text-slate-500">In</p>
                <p className="mt-1 text-sm font-extrabold">{timeOnly(row.punchIn)}</p>
              </div>
              <div className="rounded-md bg-paper px-3 py-2">
                <p className="text-[11px] font-extrabold uppercase tracking-wide text-slate-500">Out</p>
                <p className="mt-1 text-sm font-extrabold">{timeOnly(row.punchOut)}</p>
              </div>
              <div className="rounded-md bg-paper px-3 py-2">
                <p className="text-[11px] font-extrabold uppercase tracking-wide text-slate-500">Work</p>
                <p className="mt-1 text-sm font-extrabold">{formatDuration(rowWorkingMs)}</p>
              </div>
            </div>
            <div className="mt-3">
              <PunchLogList logs={logs} />
            </div>
          </article>
        );
      })}
    </div>
  );
}

function Punch({ api, user, toast }) {
  const [rows, setRows] = useState([]);
  const [busy, setBusy] = useState(false);
  const [policy, setPolicy] = useState(null);
  const [verificationType, setVerificationType] = useState("");
  const [liveNow, setLiveNow] = useState(new Date());

  async function load() {
    setRows(await api.get(`/api/attendance?month=${thisMonth()}`));
    setPolicy(await api.get("/api/attendance/policy"));
  }
  useEffect(() => { load(); }, []);
  useEffect(() => {
    const timer = setInterval(() => setLiveNow(new Date()), 1000);
    return () => clearInterval(timer);
  }, []);

  async function getLocation() {
    return new Promise((resolve, reject) => {
      if (!navigator.geolocation) return reject(new Error("GPS is not available in this browser"));
      navigator.geolocation.getCurrentPosition((pos) => resolve({ latitude: pos.coords.latitude, longitude: pos.coords.longitude }), reject, { enableHighAccuracy: true, timeout: 12000 });
    });
  }

  async function submitPunch(type, selfie = "") {
    setBusy(true);
    try {
      const location = policy?.gpsRequired === false ? {} : await getLocation();
      const deviceInfo = `${navigator.platform || "Device"} - ${navigator.userAgent}`;
      await api.post("/api/attendance/punch", { type, ...location, selfie, deviceInfo });
      await load();
      toast(type === "in" ? "Punch in saved" : "Punch out saved");
    } catch (err) {
      toast(err.message);
    } finally {
      setBusy(false);
    }
  }

  function beginPunch(type) {
    if (policy?.photoEvidenceRequired && !user.employee?.profilePhoto) {
      toast("Profile photo is required before face validation");
      return;
    }
    setVerificationType(type);
  }

  async function finishVerifiedPunch(selfie) {
    const type = verificationType;
    setVerificationType("");
    await submitPunch(type, selfie);
  }

  const photoBlocked = policy?.photoEvidenceRequired && !user.employee?.profilePhoto;
  const punchDisabled = busy || !policy || photoBlocked || Boolean(verificationType);
  const todayRow = rows.find((row) => row.date === today());
  const todayLogs = attendanceLogs(todayRow);
  const lastLog = todayLogs.at(-1);
  const isWorking = lastLog?.type === "in";
  const liveWorkedMs = punchLogsDurationMs(todayLogs, liveNow);
  const liveClock = liveNow.toLocaleTimeString("en-IN", { timeZone: COMPANY_TIME_ZONE, hour: "2-digit", minute: "2-digit", second: "2-digit" });
  const activePunchIn = isWorking ? lastLog : todayLogs.filter((log) => log.type === "in").at(-1);

  return (
    <div className="mx-auto grid min-w-0 max-w-5xl gap-4 xl:grid-cols-[.92fr_1.08fr]">
      <section className="min-w-0 rounded-xl bg-charcoal p-5 text-white shadow-lift">
        <div className="flex items-start justify-between gap-4">
          <div>
            <p className="text-xs font-extrabold uppercase tracking-[0.2em] text-brand">Mobile self attendance</p>
            <h2 className="mt-2 text-2xl font-extrabold">Punch in / Punch out</h2>
          </div>
          <BrandMark compact />
        </div>
        <div className={cx("mt-5 rounded-lg border p-4", isWorking ? "border-emerald-300/40 bg-emerald-400/10" : "border-white/10 bg-white/5")}>
          <div className="mb-4 flex flex-wrap items-center justify-between gap-2">
            <div>
              <p className="text-xs font-extrabold uppercase tracking-wide text-white/50">Clock state</p>
              <p className="mt-1 text-xl font-extrabold">{isWorking ? "Clocked in" : todayRow?.punchOut ? "Clocked out" : "Ready to clock in"}</p>
            </div>
            {activePunchIn?.time && <span className="rounded-full bg-white/10 px-3 py-1 text-xs font-bold text-white">In {timeOnly(activePunchIn.time)}</span>}
          </div>
          <div className="grid gap-3 sm:grid-cols-3">
            <div>
              <p className="text-xs font-extrabold uppercase tracking-wide text-white/50">{isWorking ? "Live clock after punch in" : "Current time"}</p>
              <p className="mt-1 text-3xl font-extrabold">{liveClock}</p>
            </div>
            <div>
              <p className="text-xs font-extrabold uppercase tracking-wide text-white/50">{isWorking ? "Live working time" : "Working time"}</p>
              <p className="mt-1 text-3xl font-extrabold text-brand">{formatDuration(liveWorkedMs)}</p>
            </div>
            <div>
              <p className="text-xs font-extrabold uppercase tracking-wide text-white/50">Status</p>
              <p className="mt-1 text-xl font-extrabold">{isWorking ? "Working now" : todayRow?.punchOut ? "Shift closed" : "Ready"}</p>
            </div>
          </div>
          {policy && (
            <div className="mt-4 flex flex-wrap gap-2 text-xs font-bold">
              <span className="rounded-full bg-brand px-3 py-1 text-charcoal">GPS {policy.gpsRequired ? "required" : "off"}</span>
              <span className="rounded-full bg-white/10 px-3 py-1 text-white">Selfie required</span>
              <span className="rounded-full bg-white/10 px-3 py-1 text-white">Face match {policy.photoEvidenceRequired ? "on" : "off"}</span>
            </div>
          )}
        </div>
        {photoBlocked && <p className="mt-3 rounded-md border border-amber-300 bg-amber-100 px-3 py-2 text-sm font-bold text-amber-950">Profile photo is required before face validation can run.</p>}
        <div className="mt-5 grid min-w-0 gap-3 sm:grid-cols-2">
          <Button className="min-h-16 text-base" disabled={punchDisabled} onClick={() => beginPunch("in")}>Punch In</Button>
          <Button className="min-h-16 text-base" tone="dark" disabled={punchDisabled} onClick={() => beginPunch("out")}>Punch Out</Button>
        </div>
      </section>
      {verificationType && (
        <div className="fixed inset-0 z-50 grid place-items-center bg-black/70 p-4">
          <div className="w-full max-w-md rounded-lg bg-white p-4 shadow-lift">
            <SectionTitle eyebrow="Face validation" title={`${verificationType === "in" ? "Punch In" : "Punch Out"} selfie`} />
            <SelfieCapture actionLabel={`Save ${verificationType === "in" ? "Punch In" : "Punch Out"}`} onCapture={finishVerifiedPunch} onCancel={() => setVerificationType("")} />
          </div>
        </div>
      )}
      <Card className={verificationType ? "xl:col-span-2" : "xl:col-span-2"}>
        <SectionTitle eyebrow="This month" title="My attendance" />
        <AttendanceCardList rows={rows} />
      </Card>
    </div>
  );
}

function Attendance({ api, user, toast, attendanceFilterPreset, setAttendanceFilterPreset }) {
  const [employees, setEmployees] = useState([]);
  const [rows, setRows] = useState([]);
  const [suspicious, setSuspicious] = useState([]);
  const [month, setMonth] = useState(thisMonth());
  const [filters, setFilters] = useState({ employeeId: "", status: "all", date: "", issue: "all", search: "" });
  const [manualOpen, setManualOpen] = useState(false);
  const [form, setForm] = useState({ employeeId: "", date: today(), status: "present", inTime: "", outTime: "", workedHours: "", notes: "" });

  async function load() {
    const emp = await api.get("/api/employees");
    setEmployees(emp);
    setRows(await api.get(`/api/attendance?month=${month}`));
    if (user.role === "admin") setSuspicious(await api.get("/api/suspicious"));
  }
  useEffect(() => { load(); }, [month]);
  useEffect(() => {
    if (!attendanceFilterPreset) return;
    const presetDate = attendanceFilterPreset.date || today();
    setMonth(presetDate.slice(0, 7));
    setFilters({
      employeeId: attendanceFilterPreset.employeeId || "",
      status: attendanceFilterPreset.status || "all",
      date: presetDate,
      issue: attendanceFilterPreset.issue || "all",
      search: attendanceFilterPreset.search || ""
    });
    if (setAttendanceFilterPreset) setAttendanceFilterPreset(null);
  }, [attendanceFilterPreset]);

  async function saveManual(e) {
    e.preventDefault();
    const payload = {
      employeeId: form.employeeId,
      date: form.date,
      status: form.status,
      notes: form.notes
    };
    if (form.inTime) payload.punchIn = combineDateAndTime(form.date, form.inTime);
    if (form.outTime) payload.punchOut = combineDateAndTime(form.date, form.outTime);
    if (form.workedHours !== "") payload.workedHours = form.workedHours;
    await api.post("/api/attendance", payload);
    setForm({ ...form, inTime: "", outTime: "", workedHours: "", notes: "" });
    await load();
    setManualOpen(false);
    toast("Attendance saved");
  }

  async function review(id, adminStatus) {
    await api.put(`/api/suspicious/${id}`, { adminStatus });
    await load();
  }

  const employeeName = (row) => row.employee?.name || employees.find((employee) => employee.id === row.employeeId)?.name || row.employeeId;
  const statusOptions = ["present", "absent", "half_day", "paid_leave", "unpaid_leave", "holiday", "weekly_off"];
  const filteredRows = rows.filter((row) => {
    const name = employeeName(row).toLowerCase();
    const search = filters.search.trim().toLowerCase();
    if (filters.employeeId && row.employeeId !== filters.employeeId) return false;
    if (filters.status !== "all" && row.status !== filters.status) return false;
    if (filters.date && row.date !== filters.date) return false;
    if (search && !`${name} ${row.date} ${row.status} ${row.notes || ""}`.toLowerCase().includes(search)) return false;
    if (filters.issue === "late" && Number(row.lateMinutes || 0) <= 0) return false;
    if (filters.issue === "overtime" && Number(row.overtimeHours || 0) <= 0) return false;
    if (filters.issue === "missing_punch" && row.punchIn && row.punchOut) return false;
    if (filters.issue === "notes" && !row.notes) return false;
    return true;
  });
  function defaultDateForMonth(nextMonth) {
    return nextMonth === thisMonth() ? today() : `${nextMonth}-01`;
  }
  function changeMonth(nextMonth) {
    setMonth(nextMonth);
    setFilters({ ...filters, date: "" });
  }
  function changeFilterDate(nextDate) {
    setFilters({ ...filters, date: nextDate });
    if (nextDate && nextDate.slice(0, 7) !== month) setMonth(nextDate.slice(0, 7));
  }
  const resetFilters = () => {
    setMonth(thisMonth());
    setFilters({ employeeId: "", status: "all", date: "", issue: "all", search: "" });
  };
  const attendanceSummary = [
    ["Rows", filteredRows.length],
    ["Present", filteredRows.filter((row) => row.status === "present").length],
    ["Late", filteredRows.filter((row) => Number(row.lateMinutes || 0) > 0).length],
    ["Missing punch", filteredRows.filter((row) => !row.punchIn || !row.punchOut).length]
  ];
  const selectedEmployee = employees.find((employee) => employee.id === filters.employeeId);
  const attendanceTitle = filters.date
    ? `Attendance - ${selectedEmployee?.name || (filters.employeeId ? "Selected employee" : "All employees")} - ${filters.date}`
    : (filters.employeeId ? `Monthly attendance - ${selectedEmployee?.name || "Selected employee"}` : "Monthly attendance");
  function combineDateAndTime(date, time) {
    if (!date || !time) return "";
    return new Date(`${date}T${time}:00+05:30`).toISOString();
  }
  function timeInputValue(value) {
    if (!value) return "";
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) return "";
    const parts = Object.fromEntries(new Intl.DateTimeFormat("en-GB", { timeZone: COMPANY_TIME_ZONE, hour: "2-digit", minute: "2-digit", hour12: false }).formatToParts(date).filter((part) => part.type !== "literal").map((part) => [part.type, part.value]));
    return `${String(parts.hour === "24" ? "00" : parts.hour).padStart(2, "0")}:${String(parts.minute).padStart(2, "0")}`;
  }
  function calculatedWorkedHours(inTime, outTime) {
    if (!inTime || !outTime) return 0;
    const [inHours, inMinutes] = inTime.split(":").map(Number);
    const [outHours, outMinutes] = outTime.split(":").map(Number);
    let minutes = (outHours * 60 + outMinutes) - (inHours * 60 + inMinutes);
    if (minutes < 0) minutes += 24 * 60;
    return Number((minutes / 60).toFixed(2));
  }
  function updateTimeForm(patch) {
    const next = { ...form, ...patch };
    const row = rows.find((item) => item.employeeId === next.employeeId && item.date === next.date);
    if (row && (patch.employeeId !== undefined || patch.date !== undefined)) {
      setForm({
        ...next,
        status: row.status || next.status,
        inTime: timeInputValue(row.punchIn),
        outTime: timeInputValue(row.punchOut),
        workedHours: row.workedHours ?? "",
        notes: row.notes || ""
      });
      return;
    }
    setForm(next);
  }
  function openManualUpdate() {
    const defaultDate = filters.date || (today().startsWith(month) ? today() : `${month}-01`);
    updateTimeForm({ employeeId: filters.employeeId || form.employeeId, date: defaultDate, inTime: "", outTime: "", workedHours: "", notes: "" });
    setManualOpen(true);
  }

  return (
    <div className="grid gap-4">
      <Card>
        <div className="mb-4">
          <div>
            <h2 className="text-lg font-bold">{user.role === "admin" ? "Monthly attendance filter" : "My monthly attendance"}</h2>
            <p className="mt-1 text-sm text-slate-500">{user.role === "admin" ? (filters.employeeId ? `${selectedEmployee?.name || "Selected employee"} for ${filters.date || month}` : `All employees for ${filters.date || month}`) : `Your attendance for ${filters.date || month}`}</p>
          </div>
        </div>
        <div className="grid gap-3 md:grid-cols-6 md:items-end">
          <Field label="Month"><Input type="month" value={month} onChange={(e) => changeMonth(e.target.value)} /></Field>
          {user.role === "admin" && (
            <Field label="Employee to view"><Select value={filters.employeeId} onChange={(e) => setFilters({ ...filters, employeeId: e.target.value })}><option value="">All employees</option>{employees.map((employee) => <option key={employee.id} value={employee.id}>{employee.name}</option>)}</Select></Field>
          )}
          <Field label="Status"><Select value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}><option value="all">All status</option>{statusOptions.map((status) => <option key={status} value={status}>{status.replaceAll("_", " ")}</option>)}</Select></Field>
          <Field label="Date"><Input type="date" value={filters.date} onChange={(e) => changeFilterDate(e.target.value)} /></Field>
          <Field label="Issue"><Select value={filters.issue} onChange={(e) => setFilters({ ...filters, issue: e.target.value })}><option value="all">All rows</option><option value="late">Late only</option><option value="overtime">Overtime only</option><option value="missing_punch">Missing punch</option><option value="notes">Notes added</option></Select></Field>
          <Field label="Search"><Input value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} placeholder="Name, note, date" /></Field>
          <Button tone="secondary" onClick={resetFilters}>Reset</Button>
        </div>
      </Card>
      {user.role === "admin" && (
        <Card>
          <div className="flex flex-col justify-between gap-3 sm:flex-row sm:items-center">
            <div>
              <h3 className="font-bold">Attendance time update</h3>
              <p className="mt-1 text-sm text-slate-500">Fill missing in/out time for one employee and save it.</p>
            </div>
            <Button tone="dark" onClick={manualOpen ? () => setManualOpen(false) : openManualUpdate}>{manualOpen ? "Close update control" : "Open update control"}</Button>
          </div>
          {manualOpen && (
            <form className="mt-4 grid gap-3 md:grid-cols-8" onSubmit={saveManual}>
              <Field label="Employee"><Select value={form.employeeId} onChange={(e) => updateTimeForm({ employeeId: e.target.value })} required><option value="">Select</option>{employees.map((e) => <option key={e.id} value={e.id}>{e.name}</option>)}</Select></Field>
              <Field label="Date"><Input type="date" value={form.date} onChange={(e) => updateTimeForm({ date: e.target.value })} /></Field>
              <Field label="Status"><Select value={form.status} onChange={(e) => updateTimeForm({ status: e.target.value })}>{["present", "absent", "half_day", "paid_leave", "unpaid_leave", "holiday", "weekly_off"].map((s) => <option key={s}>{s}</option>)}</Select></Field>
              <Field label="In time"><Input type="time" value={form.inTime} onChange={(e) => updateTimeForm({ inTime: e.target.value })} /></Field>
              <Field label="Out time"><Input type="time" value={form.outTime} onChange={(e) => updateTimeForm({ outTime: e.target.value })} /></Field>
              <Field label="Worked hours"><Input type="number" step="0.25" placeholder={form.inTime && form.outTime ? String(calculatedWorkedHours(form.inTime, form.outTime)) : "Auto"} value={form.workedHours} onChange={(e) => updateTimeForm({ workedHours: e.target.value })} /></Field>
              <Field label="Notes"><Input value={form.notes} onChange={(e) => updateTimeForm({ notes: e.target.value })} /></Field>
              <div className="flex items-end"><Button className="w-full">Save time</Button></div>
            </form>
          )}
        </Card>
      )}
      <Card>
        <div className="mb-3 flex flex-wrap justify-between gap-2">
          <div>
            <h3 className="font-bold">{attendanceTitle}</h3>
            <span className="mt-1 inline-block rounded-md bg-paper px-3 py-2 text-sm font-bold text-slate-600">{filteredRows.length} rows</span>
          </div>
          <div className="flex flex-wrap gap-2">
            <Button tone="secondary" onClick={() => downloadCsv(filteredRows, `attendance-${filters.employeeId || "all"}-${month}.csv`)}>CSV</Button>
            <Button tone="secondary" onClick={() => exportPdf("Attendance Report", filteredRows)}>PDF</Button>
          </div>
        </div>
        <div className="mb-4 grid gap-2 sm:grid-cols-4">
          {attendanceSummary.map(([label, value]) => (
            <div key={label} className="rounded-md border border-line bg-paper px-3 py-2">
              <p className="text-[11px] font-bold uppercase tracking-wide text-slate-500">{label}</p>
              <p className="mt-1 text-lg font-extrabold text-ink">{value}</p>
            </div>
          ))}
        </div>
        <DataTable rows={filteredRows} columns={[
          { key: "employee", label: "Employee", render: (r) => employeeName(r) },
          { key: "date", label: "Date" },
          { key: "status", label: "Status", render: (r) => <StatusPill value={r.status} /> },
          { key: "punchIn", label: "In", render: (r) => timeOnly(r.punchIn) },
          { key: "punchOut", label: "Out", render: (r) => timeOnly(r.punchOut) },
          { key: "punchLogs", label: "Logs", render: (r) => <PunchLogList logs={attendanceLogs(r)} /> },
          ...(user.role === "admin" ? [{ key: "evidence", label: "Evidence", render: (r) => <EvidenceCell row={r} /> }] : []),
          { key: "workedHours", label: "Hours" },
          { key: "overtimeHours", label: "OT" },
          { key: "lateMinutes", label: "Late" },
          { key: "notes", label: "Notes" }
        ]} />
      </Card>
      {user.role === "admin" && (
        <Card>
          <h3 className="mb-3 font-bold">Suspicious attendance attempts</h3>
          <DataTable rows={suspicious} columns={[
            { key: "employee", label: "Employee", render: (r) => r.employee?.name || r.employeeId },
            { key: "createdAt", label: "Time", render: (r) => `${shortDate(r.createdAt)} ${timeOnly(r.createdAt)}` },
            { key: "reason", label: "Reason" },
            { key: "adminStatus", label: "Status", render: (r) => <StatusPill value={r.adminStatus} /> },
            { key: "actions", label: "Actions", render: (r) => <div className="flex gap-2"><Button tone="secondary" onClick={() => review(r.id, "approved")}>Approve</Button><Button tone="danger" onClick={() => review(r.id, "rejected")}>Reject</Button></div> }
          ]} />
        </Card>
      )}
    </div>
  );
}

function Leaves({ api, user, toast }) {
  const [rows, setRows] = useState([]);
  const [employees, setEmployees] = useState([]);
  const [form, setForm] = useState({ employeeId: "", type: "Casual leave", startDate: today(), endDate: today(), days: 1, paid: true, reason: "" });
  const computedLeaveDays = (() => {
    const start = new Date(`${form.startDate}T00:00:00+05:30`);
    const end = new Date(`${form.endDate}T00:00:00+05:30`);
    if (!form.startDate || !form.endDate || Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end < start) return 0;
    return Math.floor((end - start) / 86400000) + 1;
  })();

  async function load() {
    setRows(await api.get("/api/leaves"));
    if (user.role === "admin") setEmployees(await api.get("/api/employees"));
  }
  useEffect(() => { load(); }, []);

  async function apply(e) {
    e.preventDefault();
    const payload = user.role === "admin" ? form : { type: form.type, startDate: form.startDate, endDate: form.endDate, reason: form.reason };
    await api.post("/api/leaves", payload);
    await load();
    toast("Leave saved");
  }

  async function update(id, status) {
    await api.put(`/api/leaves/${id}`, { status, adminNote: status });
    await load();
  }

  return (
    <div className="grid gap-4 xl:grid-cols-[380px_1fr]">
      <Card>
        <h2 className="mb-3 text-lg font-bold">{user.role === "admin" ? "Add leave" : "Apply leave"}</h2>
        <form className="grid gap-3" onSubmit={apply}>
          {user.role === "admin" && <Field label="Employee"><Select value={form.employeeId} onChange={(e) => setForm({ ...form, employeeId: e.target.value })} required><option value="">Select</option>{employees.map((e) => <option key={e.id} value={e.id}>{e.name}</option>)}</Select></Field>}
          <Field label="Leave type"><Select value={form.type} onChange={(e) => setForm({ ...form, type: e.target.value })}>{["Casual leave", "Sick leave", "Paid leave", "Unpaid leave"].map((x) => <option key={x}>{x}</option>)}</Select></Field>
          <div className="grid gap-3 sm:grid-cols-2">
            <Field label="Start"><Input type="date" value={form.startDate} onChange={(e) => setForm({ ...form, startDate: e.target.value })} /></Field>
            <Field label="End"><Input type="date" value={form.endDate} onChange={(e) => setForm({ ...form, endDate: e.target.value })} /></Field>
          </div>
          {user.role === "admin" ? (
            <div className="grid gap-3 sm:grid-cols-2">
              <Field label="Days"><Input type="number" step="0.5" value={form.days} onChange={(e) => setForm({ ...form, days: e.target.value })} /></Field>
              <Field label="Paid"><Select value={String(form.paid)} onChange={(e) => setForm({ ...form, paid: e.target.value === "true" })}><option value="true">Paid</option><option value="false">Unpaid</option></Select></Field>
            </div>
          ) : (
            <div className="rounded-md border border-line bg-slate-50 px-3 py-2 text-sm font-semibold text-slate-700">
              Days requested: {computedLeaveDays || "-"}; paid/unpaid is decided by policy/admin.
            </div>
          )}
          <Field label="Reason"><Input value={form.reason} onChange={(e) => setForm({ ...form, reason: e.target.value })} /></Field>
          <Button>{user.role === "admin" ? "Save leave" : "Apply"}</Button>
        </form>
      </Card>
      <Card>
        <h2 className="mb-3 text-lg font-bold">Leave records</h2>
        <DataTable rows={rows} columns={[
          { key: "employee", label: "Employee", render: (r) => r.employee?.name || r.employeeId },
          { key: "type", label: "Type" },
          { key: "startDate", label: "Start" },
          { key: "endDate", label: "End" },
          { key: "days", label: "Days" },
          { key: "paid", label: "Paid", render: (r) => r.paid ? "Yes" : "No" },
          { key: "status", label: "Status", render: (r) => <StatusPill value={r.status} /> },
          ...(user.role === "admin" ? [{ key: "actions", label: "Actions", render: (r) => <div className="flex gap-2"><Button tone="secondary" onClick={() => update(r.id, "approved")}>Approve</Button><Button tone="danger" onClick={() => update(r.id, "rejected")}>Reject</Button></div> }] : [])
        ]} />
      </Card>
    </div>
  );
}

function Holidays({ api, user, toast }) {
  const [rows, setRows] = useState([]);
  const [form, setForm] = useState({ name: "", date: today(), type: "public", paid: true, notes: "" });
  async function load() { setRows(await api.get("/api/holidays")); }
  useEffect(() => { load(); }, []);
  async function save(e) {
    e.preventDefault();
    await api.post("/api/holidays", form);
    setForm({ name: "", date: today(), type: "public", paid: true, notes: "" });
    await load();
    toast("Holiday saved");
  }
  async function remove(row) {
    if (!window.confirm(`Delete holiday ${row.name} on ${row.date}?`)) return;
    await api.del(`/api/holidays/${row.id}?confirm=true`);
    await load();
  }
  return (
    <div className="grid gap-4 xl:grid-cols-[380px_1fr]">
      {user.role === "admin" && (
        <Card>
          <h2 className="mb-3 text-lg font-bold">Add holiday or closed day</h2>
          <form className="grid gap-3" onSubmit={save}>
            <Field label="Name"><Input value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} required /></Field>
            <Field label="Date"><Input type="date" value={form.date} onChange={(e) => setForm({ ...form, date: e.target.value })} /></Field>
            <Field label="Type"><Select value={form.type} onChange={(e) => setForm({ ...form, type: e.target.value })}><option value="public">Public holiday</option><option value="office_closed">Office closed</option><option value="weekly_off">Weekly off</option></Select></Field>
            <Field label="Paid"><Select value={String(form.paid)} onChange={(e) => setForm({ ...form, paid: e.target.value === "true" })}><option value="true">Paid</option><option value="false">Unpaid</option></Select></Field>
            <Field label="Notes"><Input value={form.notes} onChange={(e) => setForm({ ...form, notes: e.target.value })} /></Field>
            <Button>Save</Button>
          </form>
        </Card>
      )}
      <Card className={user.role !== "admin" ? "xl:col-span-2" : ""}>
        <h2 className="mb-3 text-lg font-bold">Holiday calendar</h2>
        <DataTable rows={rows} columns={[
          { key: "date", label: "Date" },
          { key: "name", label: "Name" },
          { key: "locations", label: "Location", render: (r) => Array.isArray(r.locations) && r.locations.length ? r.locations.join(", ") : compact(r.location || r.notes) },
          { key: "type", label: "Type" },
          { key: "paid", label: "Paid", render: (r) => r.paid ? "Yes" : "No" },
          ...(user.role === "admin" ? [{ key: "actions", label: "Actions", render: (r) => <Button tone="danger" onClick={() => remove(r)}>Delete</Button> }] : [])
        ]} />
      </Card>
    </div>
  );
}

function AdvanceCards({ rows, employeeName, onApprove, onReject, onDeduct, isAdmin }) {
  if (!rows?.length) return <p className="rounded-md border border-line bg-paper px-3 py-6 text-center text-sm font-bold text-slate-500">No advance records.</p>;
  return (
    <div className="grid gap-3">
      {rows.map((row) => (
        <article key={row.id} className="rounded-lg border border-line bg-white p-3 shadow-sm">
          <div className="flex items-start justify-between gap-3">
            <div className="min-w-0">
              <p className="text-xs font-extrabold uppercase tracking-wide text-brandDeep">{isAdmin ? employeeName(row) : shortDate(row.date)}</p>
              <p className="mt-1 text-xl font-extrabold">{money(row.amount)}</p>
            </div>
            <StatusPill value={row.status === "open" ? "approved" : row.status} />
          </div>
          <div className="mt-3 grid grid-cols-2 gap-2">
            <div className="rounded-md bg-paper px-3 py-2">
              <p className="text-[11px] font-extrabold uppercase tracking-wide text-slate-500">Balance</p>
              <p className="mt-1 text-sm font-extrabold">{money(row.balance)}</p>
            </div>
            <div className="rounded-md bg-paper px-3 py-2">
              <p className="text-[11px] font-extrabold uppercase tracking-wide text-slate-500">Date</p>
              <p className="mt-1 text-sm font-extrabold">{row.date}</p>
            </div>
          </div>
          <p className="mt-3 rounded-md bg-slate-50 px-3 py-2 text-sm font-semibold text-slate-700">{row.reason || row.sourcePurpose || "No purpose added"}</p>
          {row.adminNote && <p className="mt-2 text-xs font-bold text-slate-500">Admin note: {row.adminNote}</p>}
          {isAdmin && (
            <div className="mt-3 flex flex-wrap gap-2">
              {row.status === "requested" && <Button tone="secondary" onClick={() => onApprove(row)}>Approve</Button>}
              {row.status === "requested" && <Button tone="danger" onClick={() => onReject(row)}>Reject</Button>}
              {row.status === "open" && <Button tone="secondary" onClick={() => onDeduct(row)}>Mark deducted</Button>}
            </div>
          )}
        </article>
      ))}
    </div>
  );
}

function Advances({ api, user, toast }) {
  const [rows, setRows] = useState([]);
  const [employees, setEmployees] = useState([]);
  const [filters, setFilters] = useState({ status: user.role === "admin" ? "requested" : "all", employeeId: "", source: "all", search: "", month: thisMonth() });
  const [form, setForm] = useState({ employeeId: "", amount: "", date: today(), reason: "" });
  async function load() {
    setRows(await api.get("/api/advances"));
    if (user.role === "admin") setEmployees(await api.get("/api/employees"));
  }
  useEffect(() => { load(); }, []);
  async function save(e) {
    e.preventDefault();
    const payload = user.role === "admin" ? form : { amount: form.amount, date: form.date, reason: form.reason };
    await api.post("/api/advances", payload);
    setForm({ employeeId: "", amount: "", date: today(), reason: "" });
    await load();
    toast(user.role === "admin" ? "Advance saved" : "Advance request sent");
  }
  async function updateStatus(row, status, balance = row.balance) {
    await api.put(`/api/advances/${row.id}`, { status, balance, confirmStatusChange: true });
    await load();
  }
  async function clearApprovedAdvances() {
    const openRows = rows.filter((row) => {
      if (row.status !== "open" || Number(row.balance || 0) <= 0) return false;
      if (filters.month && !String(row.date || "").startsWith(filters.month)) return false;
      if (filters.employeeId && row.employeeId !== filters.employeeId) return false;
      if (filters.source === "salary_app" && row.sourceApp !== "flyersbay_salary_portal") return false;
      if (filters.source === "manual" && row.sourceApp === "flyersbay_salary_portal") return false;
      return true;
    });
    if (!openRows.length) {
      toast("No approved outstanding advances to clear");
      return;
    }
    const total = openRows.reduce((sum, row) => sum + Number(row.balance || 0), 0);
    if (!window.confirm(`Clear ${openRows.length} approved advance(s) with outstanding balance ${money(total)}?`)) return;
    const result = await api.post("/api/advances/clear", { month: filters.month, employeeId: filters.employeeId, source: filters.source, confirmClear: true });
    await load();
    toast(`Cleared ${result.count} advance(s)`);
  }
  const employeeName = (row) => row.employee?.name || employees.find((employee) => employee.id === row.employeeId)?.name || row.employeeId;
  const sourceLabel = (row) => row.sourceApp === "flyersbay_salary_portal" ? "Salary App balance" : row.status === "requested" ? "Employee request" : "Manual";
  const purposeLabel = (row) => row.sourcePurpose || row.reason || "-";
  const approvedRows = rows.filter((row) => ["open", "deducted"].includes(row.status));
  const monthApprovedRows = approvedRows.filter((row) => String(row.date || "").startsWith(filters.month));
  const filteredRows = rows.filter((row) => {
    const search = filters.search.trim().toLowerCase();
    if (filters.status !== "all" && row.status !== filters.status) return false;
    if (filters.employeeId && row.employeeId !== filters.employeeId) return false;
    if (filters.source === "salary_app" && row.sourceApp !== "flyersbay_salary_portal") return false;
    if (filters.source === "manual" && row.sourceApp === "flyersbay_salary_portal") return false;
    if (filters.month && !String(row.date || "").startsWith(filters.month)) return false;
    if (search && !`${employeeName(row)} ${purposeLabel(row)} ${row.reason || ""} ${row.date || ""}`.toLowerCase().includes(search)) return false;
    return true;
  });
  const advanceSummary = user.role === "admin" ? [
    ["Requests", rows.filter((row) => row.status === "requested").length],
    ["Outstanding", money(rows.filter((row) => row.status === "open").reduce((sum, row) => sum + Number(row.balance || 0), 0))],
    ["Approved month", money(monthApprovedRows.reduce((sum, row) => sum + Number(row.amount || 0), 0))]
  ] : [
    ["Approved month", money(monthApprovedRows.reduce((sum, row) => sum + Number(row.amount || 0), 0))],
    ["Outstanding", money(rows.filter((row) => row.status === "open").reduce((sum, row) => sum + Number(row.balance || 0), 0))],
    ["Requests", rows.filter((row) => row.status === "requested").length]
  ];
  const sortedRows = [...filteredRows].sort((a, b) => String(b.date || "").localeCompare(String(a.date || "")));
  return (
    <div className="grid gap-4 xl:grid-cols-[380px_1fr]">
      <Card>
        <SectionTitle eyebrow={user.role === "admin" ? "Advance entry" : "Employee request"} title={user.role === "admin" ? "Add approved advance" : "Request advance"} />
        <form className="grid gap-3" onSubmit={save}>
          {user.role === "admin" && <Field label="Employee"><Select value={form.employeeId} onChange={(e) => setForm({ ...form, employeeId: e.target.value })} required><option value="">Select</option>{employees.map((e) => <option key={e.id} value={e.id}>{e.name}</option>)}</Select></Field>}
          <Field label="Amount"><Input type="number" min="1" value={form.amount} onChange={(e) => setForm({ ...form, amount: e.target.value })} required /></Field>
          <Field label="Date"><Input type="date" value={form.date} onChange={(e) => setForm({ ...form, date: e.target.value })} /></Field>
          <Field label="Reason"><Input value={form.reason} onChange={(e) => setForm({ ...form, reason: e.target.value })} placeholder="Purpose" required /></Field>
          <Button>{user.role === "admin" ? "Save approved advance" : "Send request"}</Button>
        </form>
      </Card>
      <Card>
        <SectionTitle
          eyebrow={filters.month}
          title={user.role === "admin" ? "Advance requests" : "My advances"}
          action={user.role === "admin" ? <div className="flex flex-wrap gap-2"><Button tone="danger" onClick={clearApprovedAdvances}>Clear approved</Button><Button tone="secondary" onClick={() => downloadCsv(filteredRows, "advances.csv")}>CSV</Button><Button tone="secondary" onClick={() => exportPdf("Advance Report", filteredRows)}>PDF</Button></div> : null}
        />
        <div className="mb-4 grid gap-2 sm:grid-cols-3">
          {advanceSummary.map(([label, value]) => (
            <div key={label} className="rounded-md border border-line bg-paper px-3 py-2">
              <p className="text-[11px] font-bold uppercase tracking-wide text-slate-500">{label}</p>
              <p className="mt-1 text-lg font-extrabold text-ink">{value}</p>
            </div>
          ))}
        </div>
        <div className="mb-4 grid gap-3 md:grid-cols-5 md:items-end">
          <Field label="Month"><Input type="month" value={filters.month} onChange={(e) => setFilters({ ...filters, month: e.target.value })} /></Field>
          {user.role === "admin" && <Field label="Employee"><Select value={filters.employeeId} onChange={(e) => setFilters({ ...filters, employeeId: e.target.value })}><option value="">All employees</option>{employees.map((employee) => <option key={employee.id} value={employee.id}>{employee.name}</option>)}</Select></Field>}
          <Field label="Status"><Select value={filters.status} onChange={(e) => setFilters({ ...filters, status: e.target.value })}><option value="requested">Requested</option><option value="open">Approved outstanding</option><option value="deducted">Deducted</option><option value="rejected">Rejected</option><option value="cancelled">Cancelled</option><option value="all">All status</option></Select></Field>
          {user.role === "admin" && <Field label="Source"><Select value={filters.source} onChange={(e) => setFilters({ ...filters, source: e.target.value })}><option value="all">All sources</option><option value="salary_app">Salary App</option><option value="manual">Manual/request</option></Select></Field>}
          <Field label="Search"><Input value={filters.search} onChange={(e) => setFilters({ ...filters, search: e.target.value })} placeholder="Name or purpose" /></Field>
        </div>
        {user.role === "admin" ? (
          <DataTable rows={sortedRows} columns={[
            { key: "employee", label: "Employee", render: (r) => employeeName(r) },
            { key: "date", label: "Date" },
            { key: "amount", label: "Amount", render: (r) => money(r.amount) },
            { key: "balance", label: "Balance", render: (r) => money(r.balance) },
            { key: "source", label: "Source", render: sourceLabel },
            { key: "reason", label: "Purpose", render: purposeLabel },
            { key: "status", label: "Status", render: (r) => <StatusPill value={r.status === "open" ? "approved" : r.status} /> },
            { key: "actions", label: "Actions", render: (r) => <div className="flex gap-2">{r.status === "requested" && <Button tone="secondary" onClick={() => updateStatus(r, "open", r.amount)}>Approve</Button>}{r.status === "requested" && <Button tone="danger" onClick={() => updateStatus(r, "rejected", 0)}>Reject</Button>}{r.status === "open" && <Button tone="secondary" onClick={() => updateStatus(r, "deducted", 0)}>Mark deducted</Button>}</div> }
          ]} />
        ) : (
          <AdvanceCards rows={sortedRows} employeeName={employeeName} isAdmin={false} />
        )}
      </Card>
    </div>
  );
}

function Payroll({ api, user, toast }) {
  const [month, setMonth] = useState(thisMonth());
  const [rows, setRows] = useState([]);
  const [saved, setSaved] = useState([]);
  const [deductAdvances, setDeductAdvances] = useState(false);

  async function loadPayroll(confirmIncompleteEmployeeData = false) {
    setSaved(await api.get(`/api/payroll?month=${month}`));
    if (user.role === "admin") {
      setRows(await api.post("/api/payroll/preview", { month, deductAdvances, confirmIncompleteEmployeeData }));
    } else {
      setRows([]);
    }
  }
  useEffect(() => { loadPayroll(); }, [month, deductAdvances]);

  async function finalize(confirmIncompleteEmployeeData = false) {
    const hasNegativePay = rows.some((row) => Number(row.finalSalary || 0) < 0);
    if (hasNegativePay && !window.confirm("Some final salary values are negative. Finalize anyway?")) return;
    if (deductAdvances && !window.confirm("This will apply outstanding advances in this payroll and mark them deducted. Continue?")) return;
    try {
      await api.post("/api/payroll/finalize", {
        month,
        deductAdvances,
        confirmDeductAdvances: deductAdvances,
        confirmNegativePayroll: hasNegativePay,
        confirmIncompleteEmployeeData
      });
      await loadPayroll();
      toast("Payroll finalized");
    } catch (err) {
      if (err.data?.issues?.length && !confirmIncompleteEmployeeData) {
        const previewText = err.data.issues.slice(0, 5).map((item) => `${item.employeeName}: ${item.missing.join(", ")}`).join("\n");
        if (window.confirm(`Employee statutory/document data is incomplete:\n${previewText}\n\nFinalize anyway?`)) return finalize(true);
      }
      toast(err.message);
    }
  }

  const columns = [
    { key: "employeeName", label: "Employee" },
    { key: "monthlySalary", label: "Salary", render: (r) => money(r.monthlySalary) },
    { key: "requiredWorkingDays", label: "Req days" },
    { key: "requiredWorkingHours", label: "Req hours" },
    { key: "actualWorkedHours", label: "Worked" },
    { key: "paidLeaveHours", label: "Paid leave" },
    { key: "unpaidLeaveHours", label: "Unpaid leave" },
    { key: "overtimeHours", label: "OT" },
    { key: "advanceDeduction", label: "Advance", render: (r) => money(r.advanceDeduction) },
    { key: "pfEmployerContribution", label: "PF company", render: (r) => money(Number(r.pfEmployeeSharePaidByCompany || 0) + Number(r.pfEmployerContribution || 0)) },
    { key: "esiEmployerContribution", label: "ESI company", render: (r) => money(Number(r.esiEmployeeSharePaidByCompany || 0) + Number(r.esiEmployerContribution || 0)) },
    { key: "finalSalary", label: "Net salary", render: (r) => <strong>{money(r.finalSalary)}</strong> },
    { key: "totalCompanyCost", label: "Company cost", render: (r) => money(r.totalCompanyCost) },
    { key: "slip", label: "Slip", render: (r) => <Button tone="secondary" onClick={() => createSalarySlip(r)}>PDF</Button> }
  ];
  const usingImportedSalaryRows = rows.length > 0 && rows.every((row) => row.sourceApp === "flyersbay_salary_portal");

  return (
    <div className="grid gap-4">
      <Card>
        <div className="flex flex-col justify-between gap-3 sm:flex-row sm:items-end">
          <Field label="Payroll month"><Input type="month" value={month} onChange={(e) => setMonth(e.target.value)} /></Field>
          <div className="flex flex-wrap gap-2">
            {user.role === "admin" && <Button tone="secondary" onClick={() => loadPayroll()}>Preview</Button>}
            {user.role === "admin" && <Button onClick={finalize}>Finalize payroll</Button>}
            {user.role === "admin" && <Button tone="secondary" onClick={() => downloadCsv(rows, `payroll-${month}.csv`)}>Export CSV</Button>}
          </div>
        </div>
        {user.role === "admin" && !usingImportedSalaryRows && (
          <label className="mt-3 flex items-center gap-2 text-sm font-semibold text-slate-700">
            <input type="checkbox" checked={deductAdvances} onChange={(e) => setDeductAdvances(e.target.checked)} />
            Apply outstanding advances in this payroll
          </label>
        )}
        {user.role === "admin" && usingImportedSalaryRows && (
          <div className="mt-3 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm font-semibold text-amber-900">Advance deduction is from saved Salary App payroll for this month.</div>
        )}
      </Card>
      {user.role === "admin" && (
        <>
          <Card>
            <h2 className="mb-3 text-lg font-bold">Payroll preview</h2>
            <DataTable rows={rows} columns={columns} />
          </Card>
          <div className="grid gap-4 xl:grid-cols-2">
            {rows.map((row) => (
              <Card key={row.employeeId}>
                <div className="mb-2 flex items-center justify-between">
                  <h3 className="font-bold">{row.employeeName}</h3>
                  <strong>{money(row.finalSalary)}</strong>
                </div>
                <div className="mb-3 grid gap-2 sm:grid-cols-3">
                  <div className="rounded-md bg-slate-50 px-3 py-2"><p className="text-[11px] font-bold uppercase text-slate-500">PF/ESI deduction</p><p className="font-extrabold">{money(row.statutoryEmployeeDeduction || 0)}</p></div>
                  <div className="rounded-md bg-slate-50 px-3 py-2"><p className="text-[11px] font-bold uppercase text-slate-500">Company PF/ESI</p><p className="font-extrabold">{money(row.statutoryEmployerCost)}</p></div>
                  <div className="rounded-md bg-slate-50 px-3 py-2"><p className="text-[11px] font-bold uppercase text-slate-500">Total cost</p><p className="font-extrabold">{money(row.totalCompanyCost)}</p></div>
                </div>
                <ol className="list-decimal space-y-1 pl-5 text-sm text-slate-600">
                  {row.steps.map((step, idx) => <li key={idx}>{step}</li>)}
                </ol>
              </Card>
            ))}
          </div>
        </>
      )}
      {saved.length > 0 && (
        <Card>
          <h2 className="mb-3 text-lg font-bold">Finalized salary slips</h2>
          <DataTable rows={saved} columns={[
            { key: "employee", label: "Employee", render: (r) => r.employee?.name },
            { key: "month", label: "Month" },
            { key: "paidStatus", label: "Status", render: (r) => <StatusPill value={r.paidStatus} /> },
            { key: "final", label: "Net salary", render: (r) => money(r.payload.finalSalary) },
            { key: "pdf", label: "PDF", render: (r) => <Button tone="secondary" onClick={() => createSalarySlip(r.payload)}>PDF</Button> }
          ]} />
        </Card>
      )}
    </div>
  );
}

function Reports({ api }) {
  const [type, setType] = useState("attendance");
  const [month, setMonth] = useState(thisMonth());
  const [rows, setRows] = useState([]);
  async function load() {
    setRows(await api.get(`/api/reports/${type}?month=${month}`));
  }
  useEffect(() => { load(); }, [type, month]);
  const salaryReportColumns = [
    { key: "employeeName", label: "Employee" },
    { key: "month", label: "Month" },
    { key: "grossEarnings", label: "Gross", render: (r) => money(r.grossEarnings) },
    { key: "advanceDeduction", label: "Advance", render: (r) => money(r.advanceDeduction) },
    { key: "pf", label: "PF company", render: (r) => money(Number(r.pfEmployeeSharePaidByCompany || 0) + Number(r.pfEmployerContribution || 0)) },
    { key: "esi", label: "ESI company", render: (r) => money(Number(r.esiEmployeeSharePaidByCompany || 0) + Number(r.esiEmployerContribution || 0)) },
    { key: "finalSalary", label: "Net salary", render: (r) => money(r.finalSalary) },
    { key: "totalCompanyCost", label: "Company cost", render: (r) => money(r.totalCompanyCost) },
    { key: "paidStatus", label: "Status", render: (r) => r.paidStatus ? <StatusPill value={r.paidStatus} /> : "-" }
  ];
  const columns = type === "salary" ? salaryReportColumns : rows[0] ? Object.keys(rows[0]).filter((k) => typeof rows[0][k] !== "object").slice(0, 9).map((key) => ({ key, label: key })) : [];
  return (
    <div className="grid gap-4">
      <Card>
        <div className="grid gap-3 md:grid-cols-4 md:items-end">
          <Field label="Report type"><Select value={type} onChange={(e) => setType(e.target.value)}>{["attendance", "salary", "advance", "leave", "holiday", "employee"].map((x) => <option key={x}>{x}</option>)}</Select></Field>
          <Field label="Month"><Input type="month" value={month} onChange={(e) => setMonth(e.target.value)} /></Field>
          <Button tone="secondary" onClick={() => downloadCsv(rows, `${type}-${month}.csv`)}>Export Excel CSV</Button>
          <Button tone="secondary" onClick={() => exportPdf(`${type} report`, rows)}>Export PDF</Button>
        </div>
      </Card>
      <Card>
        <DataTable rows={rows} columns={columns} />
      </Card>
    </div>
  );
}

function Settings({ api, toast }) {
  const [settings, setSettings] = useState(null);
  useEffect(() => { api.get("/api/settings").then(setSettings); }, []);
  if (!settings) return <p>Loading settings...</p>;
  const a = settings.attendance;
  const s = settings.salaryRules;
  const st = settings.statutoryRules || {};
  const setAttendance = (patch) => setSettings({ ...settings, attendance: { ...a, ...patch } });
  const setRules = (patch) => setSettings({ ...settings, salaryRules: { ...s, ...patch } });
  const setStatutory = (patch) => setSettings({ ...settings, statutoryRules: { ...st, ...patch } });
  async function save() {
    await api.put("/api/settings", settings);
    toast("Settings saved");
  }
  return (
    <div className="grid gap-4 xl:grid-cols-2">
      <Card>
        <h2 className="mb-3 text-lg font-bold">Office attendance controls</h2>
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Office latitude"><Input type="number" step="0.000001" value={a.officeLatitude} onChange={(e) => setAttendance({ officeLatitude: e.target.value })} /></Field>
          <Field label="Office longitude"><Input type="number" step="0.000001" value={a.officeLongitude} onChange={(e) => setAttendance({ officeLongitude: e.target.value })} /></Field>
          <Field label="Allowed radius meters"><Input type="number" value={a.allowedRadiusMeters} onChange={(e) => setAttendance({ allowedRadiusMeters: e.target.value })} /></Field>
          <Field label="Weekly off days">
            <Select value={a.weeklyOffDays?.[0] ?? 0} onChange={(e) => setAttendance({ weeklyOffDays: [Number(e.target.value)] })}>
              {["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"].map((d, i) => <option key={d} value={i}>{d}</option>)}
            </Select>
          </Field>
          <Field label="GPS validation"><Select value={String(a.gpsEnabled)} onChange={(e) => setAttendance({ gpsEnabled: e.target.value === "true" })}><option value="true">Enabled</option><option value="false">Disabled</option></Select></Field>
          <Field label="Photo evidence check"><Select value={String(a.faceValidationEnabled)} onChange={(e) => setAttendance({ faceValidationEnabled: e.target.value === "true" })}><option value="false">Disabled</option><option value="true">Enabled</option></Select></Field>
        </div>
      </Card>
      <Card>
        <h2 className="mb-3 text-lg font-bold">Salary calculation rules</h2>
        <div className="grid gap-3 sm:grid-cols-2">
          <Field label="Office in time"><Input type="time" value={s.officeInTime} onChange={(e) => setRules({ officeInTime: e.target.value })} /></Field>
          <Field label="Office out time"><Input type="time" value={s.officeOutTime} onChange={(e) => setRules({ officeOutTime: e.target.value })} /></Field>
          <Field label="Lunch break minutes"><Input type="number" value={s.lunchBreakMinutes} onChange={(e) => setRules({ lunchBreakMinutes: e.target.value })} /></Field>
          <Field label="Grace late minutes"><Input type="number" value={s.graceMinutes} onChange={(e) => setRules({ graceMinutes: e.target.value })} /></Field>
          <Field label="Full day hours"><Input type="number" step="0.25" value={s.fullDayHours} onChange={(e) => setRules({ fullDayHours: e.target.value })} /></Field>
          <Field label="Half day hours"><Input type="number" step="0.25" value={s.halfDayHours} onChange={(e) => setRules({ halfDayHours: e.target.value })} /></Field>
          <Field label="Holidays paid"><Select value={String(s.holidayPaid)} onChange={(e) => setRules({ holidayPaid: e.target.value === "true" })}><option value="true">Paid</option><option value="false">Unpaid</option></Select></Field>
          <Field label="Weekly off paid"><Select value={String(s.weeklyOffPaid)} onChange={(e) => setRules({ weeklyOffPaid: e.target.value === "true" })}><option value="true">Paid</option><option value="false">Unpaid</option></Select></Field>
        </div>
        <Button className="mt-4" onClick={save}>Save settings</Button>
      </Card>
      <Card className="xl:col-span-2">
        <h2 className="mb-3 text-lg font-bold">PF & ESI rules</h2>
        <div className="mb-3 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-sm font-semibold text-emerald-800">
          PF/ESI is paid by company separately. Employee salary deduction remains zero.
        </div>
        {(!st.establishmentPfCode || !st.establishmentEsiCode) && (
          <div className="mb-3 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-sm font-semibold text-amber-900">
            {[
              !st.establishmentPfCode ? "PF establishment code missing" : "",
              !st.establishmentEsiCode ? "ESI establishment code missing" : ""
            ].filter(Boolean).join("; ")}
          </div>
        )}
        <div className="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
          <Field label="PF"><Select value={String(st.pfEnabled !== false)} onChange={(e) => setStatutory({ pfEnabled: e.target.value === "true" })}><option value="true">Enabled</option><option value="false">Disabled</option></Select></Field>
          <Field label="PF wage ceiling"><Input type="number" value={st.pfWageCeiling ?? 15000} onChange={(e) => setStatutory({ pfWageCeiling: e.target.value })} /></Field>
          <Field label="PF employee share %"><Input type="number" step="0.01" value={st.pfEmployeeRate ?? 12} onChange={(e) => setStatutory({ pfEmployeeRate: e.target.value })} /></Field>
          <Field label="PF employer share %"><Input type="number" step="0.01" value={st.pfEmployerRate ?? 12} onChange={(e) => setStatutory({ pfEmployerRate: e.target.value })} /></Field>
          <Field label="EPS share %"><Input type="number" step="0.01" value={st.epsRate ?? 8.33} onChange={(e) => setStatutory({ epsRate: e.target.value })} /></Field>
          <Field label="ESI"><Select value={String(st.esiEnabled !== false)} onChange={(e) => setStatutory({ esiEnabled: e.target.value === "true" })}><option value="true">Enabled</option><option value="false">Disabled</option></Select></Field>
          <Field label="ESI wage ceiling"><Input type="number" value={st.esiWageCeiling ?? 21000} onChange={(e) => setStatutory({ esiWageCeiling: e.target.value })} /></Field>
          <Field label="ESI employee share %"><Input type="number" step="0.01" value={st.esiEmployeeRate ?? 0.75} onChange={(e) => setStatutory({ esiEmployeeRate: e.target.value })} /></Field>
          <Field label="ESI employer share %"><Input type="number" step="0.01" value={st.esiEmployerRate ?? 3.25} onChange={(e) => setStatutory({ esiEmployerRate: e.target.value })} /></Field>
          <Field label="PF code"><Input value={st.establishmentPfCode || ""} onChange={(e) => setStatutory({ establishmentPfCode: e.target.value })} /></Field>
          <Field label="ESI code"><Input value={st.establishmentEsiCode || ""} onChange={(e) => setStatutory({ establishmentEsiCode: e.target.value })} /></Field>
          <Field label="Employee share policy"><Select value={String(st.employeeContributionsPaidByCompany !== false)} onChange={(e) => setStatutory({ employeeContributionsPaidByCompany: e.target.value === "true" })}><option value="true">Company paid</option></Select></Field>
        </div>
        <Button className="mt-4" onClick={save}>Save settings</Button>
      </Card>
    </div>
  );
}

function App() {
  const [token, setToken] = useState(localStorage.getItem("staff_token") || "");
  const [user, setUser] = useState(null);
  const [screen, setScreen] = useState("dashboard");
  const [toast, setToast] = useState("");
  const [attendanceFilterPreset, setAttendanceFilterPreset] = useState(null);
  const api = useApi(token, logout);

  function showToast(message) {
    setToast(message);
    setTimeout(() => setToast(""), 4000);
  }

  function logout() {
    localStorage.removeItem("staff_token");
    setToken("");
    setUser(null);
  }

  function login(newToken, newUser) {
    localStorage.setItem("staff_token", newToken);
    setToken(newToken);
    setUser(newUser);
    setScreen(newUser.role === "admin" ? "dashboard" : "punch");
  }

  useEffect(() => {
    if (!token) return;
    api.get("/api/me").then(({ user }) => {
      setUser(user);
      setScreen(user.role === "admin" ? "dashboard" : "punch");
    }).catch(logout);
  }, [token]);

  useEffect(() => {
    if (!user) return;
    const allowed = user.role === "admin"
      ? ["dashboard", "employees", "attendance", "leaves", "holidays", "advances", "payroll", "reports", "settings"]
      : ["punch", "attendance", "leaves", "holidays", "advances", "payroll"];
    const fallback = user.role === "admin" ? "dashboard" : "punch";
    if (!allowed.includes(screen)) setScreen(fallback);
  }, [user, screen]);

  if (!token || !user) return <Login onLogin={login} />;

  const allowedScreens = user.role === "admin"
    ? ["dashboard", "employees", "attendance", "leaves", "holidays", "advances", "payroll", "reports", "settings"]
    : ["punch", "attendance", "leaves", "holidays", "advances", "payroll"];
  const defaultScreen = user.role === "admin" ? "dashboard" : "punch";
  const activeScreen = allowedScreens.includes(screen) ? screen : defaultScreen;

  const props = { api, user, toast: showToast, setScreen, attendanceFilterPreset, setAttendanceFilterPreset };
  const component = {
    dashboard: <Dashboard {...props} />,
    employees: <Employees {...props} />,
    punch: <Punch {...props} />,
    attendance: <Attendance {...props} />,
    leaves: <Leaves {...props} />,
    holidays: <Holidays {...props} />,
    advances: <Advances {...props} />,
    payroll: <Payroll {...props} />,
    reports: <Reports {...props} />,
    settings: <Settings {...props} />
  }[activeScreen] || <Dashboard {...props} />;

  return (
    <>
      <Shell user={user} screen={activeScreen} setScreen={setScreen} logout={logout}>
        {component}
      </Shell>
      <Toast toast={toast} onClose={() => setToast("")} />
    </>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
