"use client";

import { useMemo, useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Kpi, KpiStrip } from "@/components/ui/kpi";
import { useLocalStorage } from "@/lib/hooks/use-local-storage";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";
import type { Employee } from "@/lib/sag/employees-seed";
import {
  DEFAULT_PAY_SCHEDULES,
  currentPeriod,
  periodsPerYear,
  resolveSchedule,
  rollupPayroll,
  toGustoCsv,
  toQuickBooksCsv,
  type PayPeriod,
  type PayPeriodFrequency,
  type PayPeriodSchedule,
  type PayrollRollup,
  type ToastLaborRow,
} from "@/lib/hr/payroll-prep";
import { formatCurrency, formatDate } from "@/lib/utils";

// ──────────────────────────────────────────────────────────────────────────
// LocalStorage keys
// ──────────────────────────────────────────────────────────────────────────

const KEY_EMPLOYEES = "sag.hr.employees";
const KEY_SCHEDULES = "sag.hr.pay_schedules";
const KEY_LAST_EXPORT = "sag.hr.last_payroll_export";
/**
 * Reserved for a future Toast labor importer. The existing Toast CSV
 * uploader (`toast-csv-uploader.tsx`) only ingests Sales Category
 * rollups under `sag.toast.imports` — no labor rows yet. When the
 * HoursEarningsByRange importer ships, it should write
 * `ToastLaborRow[]` to this key and the rollup will pick it up.
 */
const KEY_TOAST_LABOR = "sag.toast.labor";

interface LastExport {
  at: string;
  format: "gusto" | "quickbooks";
  periodStart: string;
  periodEnd: string;
  rollupCount: number;
  entitySlug: string;
}

type FreqOverride = "auto" | PayPeriodFrequency;

const FREQ_LABELS: Record<PayPeriodFrequency, string> = {
  weekly: "Weekly",
  biweekly: "Biweekly",
  semimonthly: "Semimonthly (1st + 15th)",
  monthly: "Monthly",
};

function todayIso(): string {
  return new Date().toISOString().slice(0, 10);
}

// ──────────────────────────────────────────────────────────────────────────
// Main component
// ──────────────────────────────────────────────────────────────────────────

export function PayrollPrep() {
  const [employees] = useLocalStorage<Employee[]>(KEY_EMPLOYEES, []);
  const [scheduleOverrides, setScheduleOverrides] = useLocalStorage<PayPeriodSchedule[]>(
    KEY_SCHEDULES,
    []
  );
  const [toastLabor] = useLocalStorage<ToastLaborRow[]>(KEY_TOAST_LABOR, []);
  const [lastExport, setLastExport] = useLocalStorage<LastExport | null>(
    KEY_LAST_EXPORT,
    null
  );

  const [entityFilter, setEntityFilter] = useState<string>("all");
  const [freqOverride, setFreqOverride] = useState<FreqOverride>("auto");

  // The starting reference for the inferred period — defaults to today.
  // For "All" we still need a representative schedule, so pick the first
  // entity with employees (or fall back to the parent slug).
  const inferenceSlug = useMemo(() => {
    if (entityFilter !== "all") return entityFilter;
    const withPeople = employees.find((e) => e.status === "Active");
    return withPeople?.organizationSlug ?? "south-armz-global";
  }, [entityFilter, employees]);

  const effectiveSchedule = useMemo<PayPeriodSchedule>(() => {
    const seeded = resolveSchedule(inferenceSlug, scheduleOverrides);
    if (freqOverride === "auto") return seeded;
    return { ...seeded, frequency: freqOverride };
  }, [inferenceSlug, scheduleOverrides, freqOverride]);

  const defaultPeriod = useMemo(
    () => currentPeriod(effectiveSchedule, todayIso()),
    [effectiveSchedule]
  );

  const [periodStart, setPeriodStart] = useState(defaultPeriod.start);
  const [periodEnd, setPeriodEnd] = useState(defaultPeriod.end);
  const [payDate, setPayDate] = useState(defaultPeriod.payDate);
  const [periodDirty, setPeriodDirty] = useState(false);

  // When the user changes entity / frequency, snap dates back to the new
  // default unless they've manually edited them.
  const period: PayPeriod = useMemo(() => {
    if (periodDirty) {
      return { start: periodStart, end: periodEnd, payDate };
    }
    return defaultPeriod;
  }, [periodDirty, periodStart, periodEnd, payDate, defaultPeriod]);

  function resetPeriod() {
    setPeriodStart(defaultPeriod.start);
    setPeriodEnd(defaultPeriod.end);
    setPayDate(defaultPeriod.payDate);
    setPeriodDirty(false);
  }

  // Scope employees to the entity filter.
  const scopedEmployees = useMemo(() => {
    if (entityFilter === "all") return employees;
    return employees.filter((e) => e.organizationSlug === entityFilter);
  }, [employees, entityFilter]);

  const rollups: PayrollRollup[] = useMemo(() => {
    return rollupPayroll(
      scopedEmployees,
      toastLabor,
      period,
      // When the user overrides frequency, pass a schedule list with that
      // override applied for each scoped entity so salary slicing matches.
      freqOverride === "auto"
        ? mergedSchedules(scheduleOverrides)
        : applyFrequencyOverride(
            mergedSchedules(scheduleOverrides),
            freqOverride,
            entityFilter === "all"
              ? new Set(scopedEmployees.map((e) => e.organizationSlug))
              : new Set([entityFilter])
          )
    );
  }, [scopedEmployees, toastLabor, period, freqOverride, scheduleOverrides, entityFilter]);

  const kpis = useMemo(() => {
    let regular = 0;
    let overtime = 0;
    let gross = 0;
    for (const r of rollups) {
      regular += r.hoursRegular;
      overtime += r.hoursOvertime;
      gross += r.grossPay;
    }
    return {
      count: rollups.length,
      regular: round1(regular),
      overtime: round1(overtime),
      gross: round2(gross),
    };
  }, [rollups]);

  function download(format: "gusto" | "quickbooks") {
    if (rollups.length === 0) {
      window.alert("No employees in this rollup — add hires or expand the entity filter.");
      return;
    }
    const csv = format === "gusto" ? toGustoCsv(rollups) : toQuickBooksCsv(rollups);
    const baseName = `payroll-${format}-${period.start}_to_${period.end}${
      entityFilter !== "all" ? `-${entityFilter}` : ""
    }`;
    triggerDownload(csv, `${baseName}.csv`);
    const stamp: LastExport = {
      at: new Date().toISOString(),
      format,
      periodStart: period.start,
      periodEnd: period.end,
      rollupCount: rollups.length,
      entitySlug: entityFilter,
    };
    setLastExport(stamp);
  }

  function saveSchedule(next: PayPeriodSchedule) {
    setScheduleOverrides((prev) => {
      const others = prev.filter((s) => s.entitySlug !== next.entitySlug);
      return [...others, next];
    });
  }

  function resetSchedule(entitySlug: string) {
    setScheduleOverrides((prev) => prev.filter((s) => s.entitySlug !== entitySlug));
  }

  const labelForFilter =
    entityFilter === "all"
      ? "All entities"
      : (ALL_ORGANIZATIONS.find((o) => o.slug === entityFilter)?.name ?? entityFilter);

  return (
    <div className="space-y-6">
      {/* ─── Header strip ─────────────────────────────────────────────── */}
      <section className="grid gap-3 lg:grid-cols-[1fr_320px]">
        <Card>
          <CardContent className="p-5 space-y-4">
            <div className="flex flex-wrap items-end gap-3">
              <div className="flex flex-col gap-1">
                <label className="section-label">
                  Entity
                </label>
                <select
                  value={entityFilter}
                  onChange={(e) => {
                    setEntityFilter(e.target.value);
                    setPeriodDirty(false);
                  }}
                  className="h-9 rounded-md border border-input bg-background px-3 text-sm min-w-[16rem]"
                >
                  <option value="all">All entities</option>
                  {ALL_ORGANIZATIONS.map((o) => (
                    <option key={o.slug} value={o.slug}>
                      {o.emoji} {o.name}
                    </option>
                  ))}
                </select>
              </div>

              <div className="flex flex-col gap-1">
                <label className="section-label">
                  Pay frequency
                </label>
                <select
                  value={freqOverride}
                  onChange={(e) => {
                    setFreqOverride(e.target.value as FreqOverride);
                    setPeriodDirty(false);
                  }}
                  className="h-9 rounded-md border border-input bg-background px-3 text-sm"
                >
                  <option value="auto">
                    Auto ({FREQ_LABELS[effectiveSchedule.frequency]})
                  </option>
                  <option value="weekly">Weekly</option>
                  <option value="biweekly">Biweekly</option>
                  <option value="semimonthly">Semimonthly (1st + 15th)</option>
                  <option value="monthly">Monthly</option>
                </select>
              </div>

              <div className="flex flex-col gap-1">
                <label className="section-label">
                  Period start
                </label>
                <Input
                  type="date"
                  value={period.start}
                  onChange={(e) => {
                    setPeriodStart(e.target.value);
                    if (!periodDirty) {
                      setPeriodEnd(period.end);
                      setPayDate(period.payDate);
                    }
                    setPeriodDirty(true);
                  }}
                  className="h-9 w-40"
                />
              </div>
              <div className="flex flex-col gap-1">
                <label className="section-label">
                  Period end
                </label>
                <Input
                  type="date"
                  value={period.end}
                  onChange={(e) => {
                    setPeriodEnd(e.target.value);
                    if (!periodDirty) {
                      setPeriodStart(period.start);
                      setPayDate(period.payDate);
                    }
                    setPeriodDirty(true);
                  }}
                  className="h-9 w-40"
                />
              </div>
              <div className="flex flex-col gap-1">
                <label className="section-label">
                  Pay date
                </label>
                <Input
                  type="date"
                  value={period.payDate}
                  onChange={(e) => {
                    setPayDate(e.target.value);
                    if (!periodDirty) {
                      setPeriodStart(period.start);
                      setPeriodEnd(period.end);
                    }
                    setPeriodDirty(true);
                  }}
                  className="h-9 w-40"
                />
              </div>

              {periodDirty && (
                <Button variant="ghost" size="sm" onClick={resetPeriod}>
                  Reset to current period
                </Button>
              )}
            </div>

            <div className="text-xs text-muted-foreground tabular-nums">
              Window:{" "}
              <span className="font-mono">{period.start}</span> →{" "}
              <span className="font-mono">{period.end}</span> · Pay date{" "}
              <span className="font-mono">{period.payDate}</span> ·{" "}
              {FREQ_LABELS[effectiveSchedule.frequency]} · {labelForFilter}
            </div>

            <div className="flex flex-wrap gap-2">
              <Button variant="brand" size="sm" onClick={() => download("gusto")}>
                Download Gusto CSV
              </Button>
              <Button variant="outline" size="sm" onClick={() => download("quickbooks")}>
                Download QuickBooks CSV
              </Button>
            </div>

            {lastExport && (
              <div className="text-[11px] text-muted-foreground">
                Last export:{" "}
                <Badge variant="success" className="mr-1">
                  {lastExport.format}
                </Badge>
                {lastExport.rollupCount} row{lastExport.rollupCount === 1 ? "" : "s"} for{" "}
                <span className="font-mono">{lastExport.periodStart}</span> →{" "}
                <span className="font-mono">{lastExport.periodEnd}</span> at{" "}
                {formatDate(lastExport.at)}.
              </div>
            )}
          </CardContent>
        </Card>

        <SchedulesSidebar
          overrides={scheduleOverrides}
          onSave={saveSchedule}
          onReset={resetSchedule}
          employees={employees}
        />
      </section>

      {/* ─── KPIs ─────────────────────────────────────────────────────── */}
      <KpiStrip cols={4}>
        <Kpi label="Employees in rollup" value={String(kpis.count)} />
        <Kpi label="Regular hours" value={fmtHours(kpis.regular)} />
        <Kpi
          label="Overtime hours"
          value={fmtHours(kpis.overtime)}
          tone={kpis.overtime > 0 ? "amber" : "neutral"}
        />
        <Kpi label="Gross pay" value={formatCurrency(kpis.gross)} tone="emerald" />
      </KpiStrip>

      {/* ─── Preview table ────────────────────────────────────────────── */}
      <Card>
        <CardContent className="p-5">
          <div className="flex items-center justify-between mb-3">
            <h2 className="text-sm font-semibold">Preview rollup</h2>
            <span className="section-label">
              Active employees · scoped to filter
            </span>
          </div>
          {rollups.length === 0 ? (
            <p className="text-xs text-muted-foreground">
              No active employees match this filter. Add hires in the HR directory or
              widen the entity selection.
            </p>
          ) : (
            <div className="overflow-x-auto">
              <table className="w-full text-sm min-w-[720px]">
                <thead className="section-label border-b">
                  <tr>
                    <th className="px-2 py-2 text-left">Employee</th>
                    <th className="px-2 py-2 text-left">Entity</th>
                    <th className="px-2 py-2 text-right">Reg hrs</th>
                    <th className="px-2 py-2 text-right">OT hrs</th>
                    <th className="px-2 py-2 text-right">Rate</th>
                    <th className="px-2 py-2 text-right">Salary slice</th>
                    <th className="px-2 py-2 text-right">Commission</th>
                    <th className="px-2 py-2 text-right">Gross</th>
                    <th className="px-2 py-2 text-left">Flags</th>
                  </tr>
                </thead>
                <tbody>
                  {rollups.map((r) => {
                    const org = ALL_ORGANIZATIONS.find((o) => o.slug === r.entitySlug);
                    return (
                      <tr key={r.employeeId} className="border-b last:border-0">
                        <td className="px-2 py-2 font-medium">{r.employeeName}</td>
                        <td className="px-2 py-2 text-xs text-muted-foreground">
                          {org ? `${org.emoji} ${org.name}` : r.entitySlug}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {fmtHours(r.hoursRegular)}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {r.hoursOvertime > 0 ? (
                            <span className="text-yellow-700 dark:text-yellow-400">
                              {fmtHours(r.hoursOvertime)}
                            </span>
                          ) : (
                            fmtHours(r.hoursOvertime)
                          )}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {r.hourlyRate > 0 ? formatCurrency(r.hourlyRate) : "—"}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums">
                          {r.salaryAccrued > 0 ? formatCurrency(r.salaryAccrued) : "—"}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums text-muted-foreground">
                          {r.commissionsAccrued > 0
                            ? formatCurrency(r.commissionsAccrued)
                            : "—"}
                        </td>
                        <td className="px-2 py-2 text-right tabular-nums font-semibold">
                          {formatCurrency(r.grossPay)}
                        </td>
                        <td className="px-2 py-2 text-[11px] text-muted-foreground max-w-[260px]">
                          {r.notes.length > 0 ? (
                            <div className="space-y-0.5">
                              {r.notes.map((n) => (
                                <div key={n}>· {n}</div>
                              ))}
                            </div>
                          ) : (
                            "—"
                          )}
                        </td>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </CardContent>
      </Card>

      {/* ─── Footnotes ────────────────────────────────────────────────── */}
      <Card className="border-dashed">
        <CardContent className="p-4 text-xs text-muted-foreground space-y-1.5">
          <div>
            <strong className="text-foreground">Toast labor —</strong> The existing
            Toast importer only ingests sales (
            <code className="text-foreground">sag.toast.imports</code>); no labor /
            hours data is wired up yet. Hourly rows fall back to 0 hours with a flag
            until a HoursEarningsByRange importer ships and writes{" "}
            <code className="text-foreground">{KEY_TOAST_LABOR}</code>. Salaried
            employees still appear correctly. Commissions are a manual line you&apos;ll
            need to add for now.
          </div>
          <div>
            Source data: local-only.{" "}
            <code className="text-foreground">{KEY_EMPLOYEES}</code> ·{" "}
            <code className="text-foreground">{KEY_SCHEDULES}</code> ·{" "}
            <code className="text-foreground">{KEY_TOAST_LABOR}</code> ·{" "}
            <code className="text-foreground">{KEY_LAST_EXPORT}</code>.
          </div>
        </CardContent>
      </Card>
    </div>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Schedules sidebar — inline editor over DEFAULT_PAY_SCHEDULES
// ──────────────────────────────────────────────────────────────────────────

function SchedulesSidebar({
  overrides,
  onSave,
  onReset,
  employees,
}: {
  overrides: PayPeriodSchedule[];
  onSave: (s: PayPeriodSchedule) => void;
  onReset: (entitySlug: string) => void;
  employees: Employee[];
}) {
  const [showAll, setShowAll] = useState(false);
  const [editing, setEditing] = useState<string | null>(null);

  const entitiesWithEmployees = useMemo(() => {
    const set = new Set<string>();
    for (const e of employees) set.add(e.organizationSlug);
    return set;
  }, [employees]);

  const visibleOrgs = useMemo(() => {
    if (showAll) return ALL_ORGANIZATIONS;
    return ALL_ORGANIZATIONS.filter((o) => entitiesWithEmployees.has(o.slug));
  }, [showAll, entitiesWithEmployees]);

  return (
    <Card>
      <CardContent className="p-5 space-y-3">
        <div>
          <h2 className="text-sm font-semibold">Edit pay schedule</h2>
          <p className="text-[11px] text-muted-foreground">
            Override the default frequency per entity.{" "}
            <button
              type="button"
              className="underline hover:text-foreground"
              onClick={() => setShowAll((v) => !v)}
            >
              {showAll ? "Hide empty" : "Show all entities"}
            </button>
          </p>
        </div>
        {visibleOrgs.length === 0 ? (
          <p className="text-xs text-muted-foreground">
            No entities with employees yet — toggle &ldquo;Show all entities&rdquo; to
            edit anyway.
          </p>
        ) : (
          <div className="rounded-md border bg-card overflow-x-auto max-h-[400px] overflow-y-auto">
            <table className="w-full text-xs min-w-[480px]">
              <thead className="section-label border-b sticky top-0 bg-card">
                <tr>
                  <th className="px-2 py-2 text-left">Entity</th>
                  <th className="px-2 py-2 text-left">Frequency</th>
                  <th className="px-2 py-2 text-right">Action</th>
                </tr>
              </thead>
              <tbody>
                {visibleOrgs.map((org) => {
                  const isOverride = overrides.some((o) => o.entitySlug === org.slug);
                  const schedule = resolveSchedule(org.slug, overrides);
                  const isEditing = editing === org.slug;
                  return (
                    <ScheduleRow
                      key={org.slug}
                      orgEmoji={org.emoji ?? "🏢"}
                      orgName={org.name}
                      schedule={schedule}
                      isOverride={isOverride}
                      isEditing={isEditing}
                      onEdit={() => setEditing(org.slug)}
                      onCancel={() => setEditing(null)}
                      onSave={(s) => {
                        onSave(s);
                        setEditing(null);
                      }}
                      onReset={() => {
                        onReset(org.slug);
                        setEditing(null);
                      }}
                    />
                  );
                })}
              </tbody>
            </table>
          </div>
        )}
      </CardContent>
    </Card>
  );
}

function ScheduleRow({
  orgEmoji,
  orgName,
  schedule,
  isOverride,
  isEditing,
  onEdit,
  onCancel,
  onSave,
  onReset,
}: {
  orgEmoji: string;
  orgName: string;
  schedule: PayPeriodSchedule;
  isOverride: boolean;
  isEditing: boolean;
  onEdit: () => void;
  onCancel: () => void;
  onSave: (s: PayPeriodSchedule) => void;
  onReset: () => void;
}) {
  const [freq, setFreq] = useState<PayPeriodFrequency>(schedule.frequency);
  const [anchor, setAnchor] = useState(schedule.anchorDate);

  function start() {
    setFreq(schedule.frequency);
    setAnchor(schedule.anchorDate);
    onEdit();
  }

  function save() {
    if (!anchor) {
      window.alert("Anchor date is required.");
      return;
    }
    onSave({
      entitySlug: schedule.entitySlug,
      frequency: freq,
      anchorDate: anchor,
    });
  }

  if (isEditing) {
    return (
      <tr className="border-b last:border-0 bg-muted/30">
        <td className="px-2 py-2">
          <div className="inline-flex items-center gap-1">
            {orgEmoji} {orgName}
          </div>
        </td>
        <td className="px-2 py-2">
          <div className="flex flex-col gap-1">
            <select
              value={freq}
              onChange={(e) => setFreq(e.target.value as PayPeriodFrequency)}
              className="h-8 rounded-md border border-input bg-background px-2 text-xs"
            >
              <option value="weekly">Weekly</option>
              <option value="biweekly">Biweekly</option>
              <option value="semimonthly">Semimonthly</option>
              <option value="monthly">Monthly</option>
            </select>
            <Input
              type="date"
              value={anchor}
              onChange={(e) => setAnchor(e.target.value)}
              className="h-8 text-xs"
            />
          </div>
        </td>
        <td className="px-2 py-2 text-right">
          <div className="inline-flex items-center gap-1">
            <Button size="sm" variant="brand" onClick={save}>
              Save
            </Button>
            <Button size="sm" variant="ghost" onClick={onCancel}>
              Cancel
            </Button>
          </div>
        </td>
      </tr>
    );
  }

  return (
    <tr className="border-b last:border-0">
      <td className="px-2 py-2">
        <div className="inline-flex items-center gap-1">
          {orgEmoji} {orgName}
        </div>
        <div className="text-[10px] text-muted-foreground">
          {periodsPerYear(schedule.frequency)} periods/yr · anchor{" "}
          <span className="font-mono">{schedule.anchorDate}</span>
        </div>
      </td>
      <td className="px-2 py-2">
        <Badge variant={isOverride ? "info" : "outline"} className="text-[10px]">
          {FREQ_LABELS[schedule.frequency]}
        </Badge>
      </td>
      <td className="px-2 py-2 text-right">
        <div className="inline-flex items-center gap-1">
          <Button size="sm" variant="outline" onClick={start}>
            Edit
          </Button>
          {isOverride && (
            <Button size="sm" variant="ghost" onClick={onReset}>
              Reset
            </Button>
          )}
        </div>
      </td>
    </tr>
  );
}

// ──────────────────────────────────────────────────────────────────────────
// Helpers
// ──────────────────────────────────────────────────────────────────────────

/** Merge overrides over DEFAULT_PAY_SCHEDULES, returning one entry per entity. */
function mergedSchedules(overrides: PayPeriodSchedule[]): PayPeriodSchedule[] {
  const byEntity = new Map<string, PayPeriodSchedule>();
  for (const s of DEFAULT_PAY_SCHEDULES) byEntity.set(s.entitySlug, s);
  for (const s of overrides) byEntity.set(s.entitySlug, s);
  return Array.from(byEntity.values());
}

/**
 * Returns a new schedule list where every entity in `slugs` is forced to
 * the given frequency. Used when the user picks an explicit frequency
 * from the dropdown so the salary-slice math stays consistent.
 */
function applyFrequencyOverride(
  schedules: PayPeriodSchedule[],
  freq: PayPeriodFrequency,
  slugs: Set<string>
): PayPeriodSchedule[] {
  return schedules.map((s) =>
    slugs.has(s.entitySlug) ? { ...s, frequency: freq } : s
  );
}

function triggerDownload(content: string, filename: string) {
  const blob = new Blob([content], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

function fmtHours(n: number): string {
  return n.toFixed(1);
}

function round1(n: number): number {
  if (!Number.isFinite(n)) return 0;
  return Math.round(n * 10) / 10;
}

function round2(n: number): number {
  if (!Number.isFinite(n)) return 0;
  return Math.round(n * 100) / 100;
}
