"use client";

/**
 * HRM setup (plan K): employee types (HR-03), leave types with the design's `LeaveTypes` editor and its preview for
 * a real employee (HR-04), and the public holidays leave skips.
 */

import * as React from "react";
import { PlusIcon, Trash2Icon } from "lucide-react";

import { LeaveTypes, leaveTypeProblems, type LeaveType } from "@/components/medora/setup-more";
import { Button } from "@/components/ui/button";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { NativeSelect, NativeSelectOption } from "@/components/ui/native-select";
import { Spinner } from "@/components/ui/spinner";
import { toast } from "@/components/ui/toast";
import { HrmApi, type EmployeeRecord, type LeaveTypeRow } from "@/lib/api";

import { apiError } from "./employees-view";
import { Surface } from "@/components/medora/surface";
import { Loading } from "@/components/medora/loading";

const toDraft = (t: LeaveTypeRow): LeaveType => ({ id: String(t.id), name: t.name, days: String(t.days), carryMax: t.carryMax == null ? "" : String(t.carryMax), paid: t.paid, document: t.document, appliesTo: t.appliesTo as LeaveType["appliesTo"] });
const kindOf = (type: string | null): "Permanent" | "Contract" | "Casual" => (type === "Permanent" ? "Permanent" : type === "Casual" || type === "Piece rate" ? "Casual" : "Contract");

export function SetupView({ today, mayEmployees, mayLeave }: { today: string; mayEmployees: boolean; mayLeave: boolean }) {
  return (
    <div className="space-y-8">
      {mayLeave ? <LeaveTypesSetup today={today} /> : null}
      {mayLeave ? <HolidaysSetup today={today} /> : null}
      {mayEmployees ? <EmployeeTypesSetup /> : null}
    </div>
  );
}

function LeaveTypesSetup({ today }: { today: string }) {
  const [types, setTypes] = React.useState<LeaveType[] | null>(null);
  const [saved, setSaved] = React.useState("");
  const [emps, setEmps] = React.useState<EmployeeRecord[]>([]);
  const [who, setWho] = React.useState("");
  const [left, setLeft] = React.useState<Record<string, number>>({});
  const [busy, setBusy] = React.useState(false);
  const year = Number(today.slice(0, 4));

  const load = React.useCallback(() => {
    HrmApi.leaveTypes()
      .then((t) => {
        const d = t.map(toDraft);
        setTypes(d);
        setSaved(JSON.stringify(d));
      })
      .catch((e) => (setTypes([]), toast.add({ type: "error", title: "Couldn't load leave types", description: apiError(e, "Try again.") })));
  }, []);
  React.useEffect(() => {
    load();
    HrmApi.employees()
      .then((e) => {
        const act = e.filter((x) => x.active);
        setEmps(act);
        if (act[0]) setWho(String(act[0].id));
      })
      .catch(() => setEmps([]));
  }, [load]);
  React.useEffect(() => {
    if (!who) return;
    HrmApi.balances(year - 1)
      .then((b) => setLeft(Object.fromEntries(b.filter((x) => String(x.employeeId) === who).map((x) => [x.type, Math.max(0, x.allocated - x.taken - x.booked)]))))
      .catch(() => setLeft({}));
  }, [who, year]);

  if (!types)
    return (
      <Loading what="setup" columns={6} rows={4} />
    );
  const e = emps.find((x) => String(x.id) === who);
  const problems = types.flatMap((t) => leaveTypeProblems(t, types));
  const dirty = JSON.stringify(types) !== saved;

  const save = async () => {
    setBusy(true);
    try {
      const t = await HrmApi.saveLeaveTypes(types.map((x) => ({ ...x, id: /^\d+$/.test(x.id) ? x.id : "" })));
      const d = t.map(toDraft);
      setTypes(d);
      setSaved(JSON.stringify(d));
      toast.add({ title: "Leave types saved", description: "A type with leave booked on it is taken off the list but kept for the records." });
    } catch (err) {
      toast.add({ type: "error", title: "Not saved", description: apiError(err, "Try again.") });
    } finally {
      setBusy(false);
    }
  };

  return (
    <section className="space-y-3">
      {/* The leave types table is its own white container (data table spec), so this section is not a surface */}
      <div>
        <h2 className="text-sm font-semibold">Leave types</h2>
        <p className="text-xs text-muted-foreground">Yearly days, how many roll over into next year, who each applies to, and whether booking needs a document.</p>
      </div>
      {emps.length ? (
        <Surface>
          <Field className="w-64">
            <FieldLabel htmlFor="lt-who">Preview for</FieldLabel>
            <NativeSelect id="lt-who" value={who} onChange={(ev) => setWho(ev.target.value)}>
              {emps.map((x) => (
                <NativeSelectOption key={x.id} value={String(x.id)}>
                  {x.name}
                </NativeSelectOption>
              ))}
            </NativeSelect>
          </Field>
        </Surface>
      ) : null}
      <LeaveTypes types={types} onChange={setTypes} preview={{ name: e?.name ?? "A new permanent employee", kind: kindOf(e?.type ?? "Permanent"), gender: e?.gender === "Man" ? "Man" : "Woman", leftLastYear: left }} />
      {e && !e.gender ? <p className="text-xs text-muted-foreground">{e.name} has no gender recorded, so leave for women or men won&apos;t apply to them; the preview assumes a woman.</p> : null}
      <div className="flex justify-end gap-2">
        {dirty ? (
          <Button variant="outline" disabled={busy} onClick={() => setTypes(JSON.parse(saved) as LeaveType[])}>
            Discard changes
          </Button>
        ) : null}
        <Button disabled={busy || !dirty || problems.length > 0} onClick={() => void save()}>
          {busy ? <Spinner /> : null}
          Save leave types
        </Button>
      </div>
    </section>
  );
}

function HolidaysSetup({ today }: { today: string }) {
  const [rows, setRows] = React.useState<{ date: string; name: string }[] | null>(null);
  const [busy, setBusy] = React.useState(false);
  React.useEffect(() => {
    HrmApi.holidays()
      .then(setRows)
      .catch(() => setRows([]));
  }, []);
  if (!rows) return null;
  const dup = rows.some((r, i) => r.date && rows.findIndex((x) => x.date === r.date) !== i);
  const bad = dup || rows.some((r) => !r.date || !r.name.trim());
  const save = async () => {
    setBusy(true);
    try {
      setRows(await HrmApi.saveHolidays(rows));
      toast.add({ title: "Public holidays saved", description: "Leave booked from now on skips them." });
    } catch (e) {
      toast.add({ type: "error", title: "Not saved", description: apiError(e, "Try again.") });
    } finally {
      setBusy(false);
    }
  };
  return (
    <Surface as="section" density="comfortable" className="space-y-3">
      <div>
        <h2 className="text-sm font-semibold">Public holidays</h2>
        <p className="text-xs text-muted-foreground">Leave counts working days: weekends and these dates are left out. Add each year&apos;s dates, including Easter and Idd-ul-Fitr when they are announced.</p>
      </div>
      <div className="space-y-2">
        {rows.map((r, i) => (
          <div key={i} className="flex flex-wrap items-center gap-2">
            <Input aria-label="Date" type="date" className="w-44" value={r.date} onChange={(e) => setRows(rows.map((x, j) => (j === i ? { ...x, date: e.target.value } : x)))} />
            <Input aria-label="Holiday" className="w-64" value={r.name} placeholder="e.g. Jamhuri Day" onChange={(e) => setRows(rows.map((x, j) => (j === i ? { ...x, name: e.target.value } : x)))} />
            <Button size="icon-sm" variant="ghost" aria-label={`Remove ${r.name || "holiday"}`} onClick={() => setRows(rows.filter((_, j) => j !== i))}>
              <Trash2Icon />
            </Button>
          </div>
        ))}
        {!rows.length ? <p className="text-sm text-muted-foreground">No public holidays listed.</p> : null}
        {dup ? <p className="text-xs text-status-error-text">A date is listed twice.</p> : null}
      </div>
      <div className="flex flex-wrap justify-between gap-2">
        <Button size="sm" variant="outline" onClick={() => setRows([...rows, { date: today, name: "" }])}>
          <PlusIcon data-icon="inline-start" />
          Add holiday
        </Button>
        <Button disabled={busy || bad} onClick={() => void save()}>
          {busy ? <Spinner /> : null}
          Save public holidays
        </Button>
      </div>
    </Surface>
  );
}

function EmployeeTypesSetup() {
  const [types, setTypes] = React.useState<{ id: number; name: string; active: boolean; uses: number }[] | null>(null);
  const [names, setNames] = React.useState<Record<number, string>>({});
  const [adding, setAdding] = React.useState("");
  const load = React.useCallback(() => {
    HrmApi.types()
      .then((t) => {
        setTypes(t);
        setNames(Object.fromEntries(t.map((x) => [x.id, x.name])));
      })
      .catch(() => setTypes([]));
  }, []);
  React.useEffect(() => load(), [load]);
  if (!types) return null;
  const run = (p: Promise<unknown>, title: string) =>
    p
      .then(() => {
        toast.add({ title });
        load();
      })
      .catch((e) => toast.add({ type: "error", title: "Not saved", description: apiError(e, "Try again.") }));
  return (
    <Surface as="section" density="comfortable" className="space-y-3">
      <div>
        <h2 className="text-sm font-semibold">Employee types</h2>
        <p className="text-xs text-muted-foreground">Chosen on each employee. A type in use can be deactivated, not removed. Leave set to &ldquo;Permanent only&rdquo; follows the type named Permanent.</p>
      </div>
      <div className="space-y-2">
        {types.map((t) => (
          <div key={t.id} className="flex flex-wrap items-center gap-2">
            <Input aria-label={`${t.name} name`} className="w-56" value={names[t.id] ?? ""} onChange={(e) => setNames({ ...names, [t.id]: e.target.value })} disabled={!t.active} />
            <span className="w-28 text-xs text-muted-foreground">{t.uses === 1 ? "1 employee" : `${t.uses} employees`}</span>
            {names[t.id]?.trim() && names[t.id].trim() !== t.name ? (
              <Button size="sm" variant="outline" onClick={() => void run(HrmApi.updateType(t.id, { name: names[t.id].trim() }), "Type renamed")}>
                Rename
              </Button>
            ) : null}
            <Button size="sm" variant="ghost" onClick={() => void run(HrmApi.updateType(t.id, { active: !t.active }), t.active ? `${t.name} deactivated` : `${t.name} reactivated`)}>
              {t.active ? "Deactivate" : "Reactivate"}
            </Button>
          </div>
        ))}
      </div>
      <div className="flex flex-wrap items-end gap-2">
        <Field className="w-56">
          <FieldLabel htmlFor="et-new">New type</FieldLabel>
          <Input id="et-new" value={adding} onChange={(e) => setAdding(e.target.value)} placeholder="e.g. Locum" />
        </Field>
        <Button size="sm" variant="outline" disabled={!adding.trim()} onClick={() => void run(HrmApi.addType(adding.trim()), "Type added").then(() => setAdding(""))}>
          <PlusIcon data-icon="inline-start" />
          Add type
        </Button>
      </div>
    </Surface>
  );
}
