"use client";

import { useMemo, useState } from "react";
import useSWR from "swr";
import {
  Download,
  FilePenLine,
  Plus,
  Printer,
  Search,
  SlidersHorizontal,
  Trash2,
  UserMinus,
  UserPlus,
} from "lucide-react";
import { toast } from "sonner";
import type { Desa, Paginated, Penduduk, Wilayah } from "@/lib/types";
import { ApiError, apiSend, fetcher } from "@/lib/api";
import { cetakHtml, escapeHtml, kopDesa } from "@/lib/cetak";
import { unduhCsv } from "@/lib/sekretariat";
import { useSession } from "@/lib/use-session";
import { PageHeader, StatCard } from "@/components/page-header";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Select } from "@/components/ui/select";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { Textarea } from "@/components/ui/textarea";
import { AGAMA_OPTIONS, formatDateShort, labelGender } from "@/lib/utils";
import { FotoPenduduk } from "@/components/admin/foto-penduduk";

interface MutasiRow {
  id: number;
  pendudukId: number | null;
  nik: string | null;
  nama: string;
  jenis: string;
  tanggal: string;
  asalTujuan: string | null;
  alasan: string | null;
  keterangan: string | null;
  createdAt?: string;
  penduduk?: {
    foto: string | null;
    jenisKelamin: string | null;
    tanggalLahir: string | null;
    rt: {
      nama: string;
      parent: { nama: string; parent: { nama: string } | null } | null;
    } | null;
    keluarga: { noKk: string; kepalaKeluarga: { nama: string } | null } | null;
  } | null;
}

const BULAN_OPTIONS = [
  "Januari",
  "Februari",
  "Maret",
  "April",
  "Mei",
  "Juni",
  "Juli",
  "Agustus",
  "September",
  "Oktober",
  "November",
  "Desember",
];

const emptyFilter = {
  jenis: "",
  tahun: "",
  bulan: "",
  jenisKelamin: "",
  agama: "",
  dusunId: "",
  rwId: "",
  rtId: "",
};

function rantaiMutasi(row: MutasiRow) {
  const rt = row.penduduk?.rt;
  const rw = rt?.parent;
  return {
    dusun: rw?.parent?.nama ?? "-",
    rw: rw?.nama ?? "-",
    rt: rt?.nama ?? "-",
  };
}

function umurSaatPeristiwa(tanggalLahir: string | null, tanggal: string) {
  if (!tanggalLahir) return "-";
  const birth = new Date(tanggalLahir);
  const event = new Date(tanggal);
  if (Number.isNaN(birth.getTime()) || Number.isNaN(event.getTime())) return "-";
  let age = event.getFullYear() - birth.getFullYear();
  const month = event.getMonth() - birth.getMonth();
  if (month < 0 || (month === 0 && event.getDate() < birth.getDate())) age -= 1;
  return age;
}

const JENIS_OPTIONS = [
  { value: "LAHIR", label: "Kelahiran", variant: "success" as const },
  { value: "PINDAH_MASUK", label: "Pindah masuk", variant: "info" as const },
  { value: "PINDAH_KELUAR", label: "Pindah keluar", variant: "warning" as const },
  { value: "MENINGGAL", label: "Meninggal dunia", variant: "danger" as const },
  { value: "HILANG", label: "Hilang", variant: "secondary" as const },
];

// Catatan warisan OpenSID memakai kode MASUK/DATANG/KELUAR/MATI; keduanya harus tetap terbaca.
const JENIS_LAMA: Record<string, string> = {
  MASUK: "PINDAH_MASUK",
  DATANG: "PINDAH_MASUK",
  KELUAR: "PINDAH_KELUAR",
  MATI: "MENINGGAL",
};

function kodeJenis(value: string) {
  return JENIS_LAMA[value] ?? value;
}

function labelJenis(value: string) {
  return JENIS_OPTIONS.find((option) => option.value === kodeJenis(value))?.label ?? value;
}

function variantJenis(value: string) {
  return (
    JENIS_OPTIONS.find((option) => option.value === kodeJenis(value))?.variant ??
    "secondary"
  );
}

type FormState = {
  pendudukId: string;
  nik: string;
  nama: string;
  jenis: string;
  tanggal: string;
  asalTujuan: string;
  alasan: string;
  keterangan: string;
};

const emptyForm: FormState = {
  pendudukId: "",
  nik: "",
  nama: "",
  jenis: "PINDAH_MASUK",
  tanggal: new Date().toISOString().slice(0, 10),
  asalTujuan: "",
  alasan: "",
  keterangan: "",
};

export default function MutasiPendudukPage() {
  const { user } = useSession();
  const canMutate = user?.role === "ADMIN" || user?.role === "OPERATOR";

  const [search, setSearch] = useState("");
  const [q, setQ] = useState("");
  const [filter, setFilter] = useState(emptyFilter);
  const [tanggalFrom, setTanggalFrom] = useState("");
  const [tanggalTo, setTanggalTo] = useState("");
  const [spesifik, setSpesifik] = useState(false);

  const [formOpen, setFormOpen] = useState(false);
  const [editing, setEditing] = useState<MutasiRow | null>(null);
  const [form, setForm] = useState<FormState>(emptyForm);
  const [saving, setSaving] = useState(false);
  const [deleteTarget, setDeleteTarget] = useState<MutasiRow | null>(null);
  const [deleting, setDeleting] = useState(false);
  const [selected, setSelected] = useState<number[]>([]);
  const [aksiTerbuka, setAksiTerbuka] = useState(false);

  const params = new URLSearchParams({ limit: "1000" });
  if (q) params.set("q", q);
  for (const [key, value] of Object.entries(filter)) {
    if (value) params.set(key, value);
  }
  if (tanggalFrom) params.set("tanggalFrom", tanggalFrom);
  if (tanggalTo) params.set("tanggalTo", tanggalTo);

  const { data, isLoading, mutate } = useSWR<MutasiRow[]>(
    `/master/mutasi-penduduk?${params.toString()}`,
    fetcher,
  );
  const { data: semua } = useSWR<MutasiRow[]>(
    "/master/mutasi-penduduk?limit=1000",
    fetcher,
  );
  const { data: pendudukList } = useSWR<Paginated<Penduduk>>(
    "/penduduk?limit=200",
    fetcher,
  );
  const { data: desa } = useSWR<Desa>("/desa", fetcher);
  const { data: wilayah } = useSWR<Wilayah[]>("/wilayah", fetcher);

  const rows = data ?? [];
  const allWilayah = wilayah ?? [];
  const dusunOptions = allWilayah.filter((item) => item.level === "DUSUN");
  const rwOptions = allWilayah.filter(
    (item) =>
      item.level === "RW" &&
      (!filter.dusunId || item.parentId === Number(filter.dusunId)),
  );
  const rtOptions = allWilayah.filter(
    (item) =>
      item.level === "RT" &&
      (!filter.rwId || item.parentId === Number(filter.rwId)),
  );
  const adaFilter =
    Boolean(q) ||
    Object.values(filter).some(Boolean) ||
    Boolean(tanggalFrom || tanggalTo);

  const tahunOptions = Array.from(
    { length: new Date().getFullYear() - 2009 },
    (_, index) => String(new Date().getFullYear() - index),
  );

  function setValue(key: keyof typeof emptyFilter, value: string) {
    setFilter((current) => ({
      ...current,
      [key]: value,
      ...(key === "dusunId" ? { rwId: "", rtId: "" } : {}),
      ...(key === "rwId" ? { rtId: "" } : {}),
    }));
  }

  const ringkasan = useMemo(() => {
    const list = semua ?? [];
    const hitung = (kode: string) =>
      list.filter((row) => kodeJenis(row.jenis) === kode).length;
    return {
      masuk: hitung("PINDAH_MASUK") + hitung("LAHIR"),
      keluar: hitung("PINDAH_KELUAR"),
      mati: hitung("MENINGGAL"),
      hilang: hitung("HILANG"),
    };
  }, [semua]);

  function update(key: keyof FormState, value: string) {
    setForm((current) => ({ ...current, [key]: value }));
  }

  function pilihPenduduk(id: string) {
    const warga = (pendudukList?.data ?? []).find(
      (item) => String(item.id) === id,
    );
    setForm((current) => ({
      ...current,
      pendudukId: id,
      nik: warga?.nik ?? current.nik,
      nama: warga?.nama ?? current.nama,
    }));
  }

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

  function openEdit(row: MutasiRow) {
    setEditing(row);
    setForm({
      pendudukId: row.pendudukId ? String(row.pendudukId) : "",
      nik: row.nik ?? "",
      nama: row.nama,
      jenis: kodeJenis(row.jenis),
      tanggal: row.tanggal.slice(0, 10),
      asalTujuan: row.asalTujuan ?? "",
      alasan: row.alasan ?? "",
      keterangan: row.keterangan ?? "",
    });
    setFormOpen(true);
  }

  async function save(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setSaving(true);
    const payload: Record<string, unknown> = {
      nama: form.nama,
      jenis: form.jenis,
      tanggal: form.tanggal,
    };
    if (form.pendudukId) payload.pendudukId = Number(form.pendudukId);
    if (form.nik) payload.nik = form.nik;
    if (form.asalTujuan) payload.asalTujuan = form.asalTujuan;
    if (form.alasan) payload.alasan = form.alasan;
    if (form.keterangan) payload.keterangan = form.keterangan;

    try {
      if (editing) {
        await apiSend(`/master/mutasi-penduduk/${editing.id}`, "PATCH", payload);
        toast.success("Riwayat mutasi diperbarui");
      } else {
        await apiSend("/master/mutasi-penduduk", "POST", payload);
        toast.success("Mutasi penduduk dicatat");
      }
      setFormOpen(false);
      await mutate();
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal menyimpan data");
    } finally {
      setSaving(false);
    }
  }

  async function remove() {
    if (!deleteTarget) return;
    setDeleting(true);
    try {
      await apiSend(`/master/mutasi-penduduk/${deleteTarget.id}`, "DELETE");
      toast.success("Riwayat mutasi dihapus");
      setDeleteTarget(null);
      await mutate();
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal menghapus data");
    } finally {
      setDeleting(false);
    }
  }

  function toggleSemua() {
    const ids = rows.map((row) => row.id);
    setSelected((current) =>
      ids.length && ids.every((id) => current.includes(id)) ? [] : ids,
    );
  }

  function toggleSatu(id: number) {
    setSelected((current) =>
      current.includes(id) ? current.filter((x) => x !== id) : [...current, id],
    );
  }

  function dataTerpilih() {
    return rows.filter((row) => selected.includes(row.id));
  }

  async function hapusTerpilih() {
    if (!selected.length) return;
    setAksiTerbuka(false);
    try {
      await Promise.all(
        selected.map((id) => apiSend(`/master/mutasi-penduduk/${id}`, "DELETE")),
      );
      toast.success(`${selected.length} catatan mutasi dihapus`);
      setSelected([]);
      await mutate();
    } catch (error) {
      toast.error(
        error instanceof ApiError ? error.message : "Gagal menghapus data terpilih",
      );
    }
  }

  function cetakDaftar(baris: MutasiRow[] = rows) {
    if (!baris.length) {
      toast.error("Belum ada data untuk dicetak");
      return;
    }
    const periode = filter.tahun
      ? `${filter.bulan ? BULAN_OPTIONS[Number(filter.bulan) - 1] + " " : ""}${filter.tahun}`
      : `${tanggalFrom || "-"} s.d. ${tanggalTo || "-"}`;
    const isi = `
      ${kopDesa(desa, "Riwayat Mutasi Penduduk")}
      <table class="info">
        <tr><td>Periode</td><td>:</td><td>${escapeHtml(periode)}</td></tr>
        <tr><td>Jenis</td><td>:</td><td>${escapeHtml(filter.jenis ? labelJenis(filter.jenis) : "Semua jenis")}</td></tr>
        <tr><td>Jumlah catatan</td><td>:</td><td>${baris.length}</td></tr>
      </table>
      <table>
        <thead><tr><th>No</th><th>NIK</th><th>Nama</th><th>No. KK / Nama KK</th><th>L/P</th><th>Dusun</th><th>RW</th><th>RT</th><th>Umur</th><th>Status Menjadi</th><th>Tgl Peristiwa</th><th>Tgl Lapor</th><th>Asal / Tujuan</th><th>Alasan</th><th>Catatan Peristiwa</th></tr></thead>
        <tbody>
          ${baris
            .map((row, index) => {
              const wilayahRow = rantaiMutasi(row);
              const kk = row.penduduk?.keluarga;
              return `<tr><td class="num">${index + 1}</td><td>${escapeHtml(row.nik ?? "-")}</td><td>${escapeHtml(row.nama)}</td><td>${escapeHtml(
                kk ? `${kk.noKk} / ${kk.kepalaKeluarga?.nama ?? "-"}` : "-",
              )}</td><td>${row.penduduk?.jenisKelamin === "L" ? "L" : "P"}</td><td>${escapeHtml(wilayahRow.dusun)}</td><td>${escapeHtml(wilayahRow.rw)}</td><td>${escapeHtml(wilayahRow.rt)}</td><td class="num">${umurSaatPeristiwa(
                row.penduduk?.tanggalLahir ?? null,
                row.tanggal,
              )}</td><td>${escapeHtml(labelJenis(row.jenis))}</td><td>${escapeHtml(new Date(row.tanggal).toLocaleDateString("id-ID"))}</td><td>${escapeHtml(row.createdAt ? new Date(row.createdAt).toLocaleDateString("id-ID") : "-")}</td><td>${escapeHtml(row.asalTujuan ?? "-")}</td><td>${escapeHtml(row.alasan ?? "-")}</td><td>${escapeHtml(row.keterangan ?? "-")}</td></tr>`;
            })
            .join("")}
        </tbody>
      </table>
      <div class="ttd">
        <div>
          <div>${escapeHtml((desa?.kecamatan ?? "Cipari").toUpperCase())}, ${new Date().toLocaleDateString("id-ID", { day: "2-digit", month: "long", year: "numeric" })}</div>
          <div>Kepala Desa ${escapeHtml((desa?.nama ?? "Mulyadadi").replace(/^Desa\s+/i, ""))}</div>
          <div class="ruang"></div>
          <div><strong>${escapeHtml(desa?.kepalaDesa ?? "-")}</strong></div>
        </div>
      </div>
    `;
    if (!cetakHtml("Riwayat Mutasi Penduduk", isi)) {
      toast.error("Izinkan pop-up untuk mencetak riwayat mutasi");
    }
  }

  function unduhDaftar(baris: MutasiRow[] = rows) {
    if (!baris.length) {
      toast.error("Belum ada data untuk diunduh");
      return;
    }
    unduhCsv(
      `riwayat-mutasi-${new Date().toISOString().slice(0, 10)}.csv`,
      [
        "NIK",
        "Nama",
        "No. KK",
        "Nama KK",
        "Jenis Kelamin",
        "Dusun",
        "RW",
        "RT",
        "Umur",
        "Status Menjadi",
        "Tgl Peristiwa",
        "Tgl Lapor",
        "Asal / Tujuan",
        "Alasan",
        "Catatan Peristiwa",
      ],
      baris.map((row) => {
        const wilayahRow = rantaiMutasi(row);
        return [
          row.nik ?? "",
          row.nama,
          row.penduduk?.keluarga?.noKk ?? "",
          row.penduduk?.keluarga?.kepalaKeluarga?.nama ?? "",
          labelGender(row.penduduk?.jenisKelamin),
          wilayahRow.dusun,
          wilayahRow.rw,
          wilayahRow.rt,
          umurSaatPeristiwa(row.penduduk?.tanggalLahir ?? null, row.tanggal),
          labelJenis(row.jenis),
          row.tanggal.slice(0, 10),
          row.createdAt ? row.createdAt.slice(0, 10) : "",
          row.asalTujuan ?? "",
          row.alasan ?? "",
          row.keterangan ?? "",
        ];
      }),
    );
    toast.success(`${baris.length} catatan mutasi diekspor`);
  }

  return (
    <div className="animate-fade-in space-y-6">
      <PageHeader
        title="Riwayat Mutasi Penduduk"
        description="Catatan kelahiran, kematian, pindah datang, dan pindah keluar penduduk."
        action={
          <div className="flex flex-wrap gap-2">
            <Button variant="outline" onClick={() => setSpesifik((value) => !value)}>
              <SlidersHorizontal className="h-4 w-4" />
              Pencarian Spesifik
            </Button>
            <Button variant="outline" onClick={() => cetakDaftar()} disabled={!rows.length}>
              <Printer className="h-4 w-4" />
              Cetak
            </Button>
            <Button variant="outline" onClick={() => unduhDaftar()} disabled={!rows.length}>
              <Download className="h-4 w-4" />
              Unduh
            </Button>
            {canMutate && (
              <div className="relative">
                <Button
                  variant="outline"
                  onClick={() => setAksiTerbuka((open) => !open)}
                  disabled={!selected.length}
                >
                  <SlidersHorizontal className="h-4 w-4" />
                  Pilih Aksi Lainnya
                  {selected.length > 0 && (
                    <span className="ml-1 rounded-full bg-white/25 px-1.5 text-xs">
                      {selected.length}
                    </span>
                  )}
                </Button>
                {aksiTerbuka && (
                  <div className="absolute right-0 z-20 mt-1 w-56 rounded-lg border bg-card p-1 shadow-lg">
                    <button
                      type="button"
                      className="block w-full rounded-md px-3 py-2 text-left text-sm hover:bg-muted"
                      onClick={() => {
                        setAksiTerbuka(false);
                        cetakDaftar(dataTerpilih());
                      }}
                    >
                      Cetak Data Terpilih
                    </button>
                    <button
                      type="button"
                      className="block w-full rounded-md px-3 py-2 text-left text-sm hover:bg-muted"
                      onClick={() => {
                        setAksiTerbuka(false);
                        unduhDaftar(dataTerpilih());
                      }}
                    >
                      Unduh Data Terpilih
                    </button>
                    <button
                      type="button"
                      className="block w-full rounded-md px-3 py-2 text-left text-sm text-destructive hover:bg-muted"
                      onClick={hapusTerpilih}
                    >
                      Hapus Data Terpilih
                    </button>
                  </div>
                )}
              </div>
            )}
            {canMutate && (
              <Button onClick={openCreate}>
                <Plus className="h-4 w-4" />
                Tambah Mutasi
              </Button>
            )}
          </div>
        }
      />

      <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
        <StatCard title="Kelahiran / masuk" value={ringkasan.masuk} icon={UserPlus} />
        <StatCard title="Pindah keluar" value={ringkasan.keluar} icon={UserMinus} tone="amber" />
        <StatCard title="Meninggal" value={ringkasan.mati} icon={UserMinus} tone="violet" />
        <StatCard title="Hilang" value={ringkasan.hilang} icon={UserMinus} tone="sky" />
      </div>

      <Card>
        <CardContent className="space-y-4 p-5">
          <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
            <form
              onSubmit={(event) => {
                event.preventDefault();
                setQ(search.trim());
              }}
              className="relative w-full lg:max-w-sm"
            >
              <Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
              <Input
                value={search}
                onChange={(event) => setSearch(event.target.value)}
                placeholder="Cari nama atau NIK…"
                className="pl-9"
              />
            </form>
            <div className="flex flex-wrap gap-2">
              <Select
                value={filter.jenis}
                onChange={(event) => setValue("jenis", event.target.value)}
                aria-label="Filter jenis mutasi"
                className="w-full sm:w-44"
              >
                <option value="">Semua jenis</option>
                {JENIS_OPTIONS.map((option) => (
                  <option key={option.value} value={option.value}>
                    {option.label}
                  </option>
                ))}
              </Select>
              <Select
                value={filter.tahun}
                onChange={(event) => setValue("tahun", event.target.value)}
                aria-label="Filter tahun"
                className="w-full sm:w-32"
              >
                <option value="">Semua tahun</option>
                {tahunOptions.map((item) => (
                  <option key={item} value={item}>
                    {item}
                  </option>
                ))}
              </Select>
              <Select
                value={filter.bulan}
                onChange={(event) => setValue("bulan", event.target.value)}
                aria-label="Filter bulan"
                className="w-full sm:w-36"
              >
                <option value="">Semua bulan</option>
                {BULAN_OPTIONS.map((nama, index) => (
                  <option key={nama} value={String(index + 1)}>
                    {nama}
                  </option>
                ))}
              </Select>
              <Select
                value={filter.dusunId}
                onChange={(event) => setValue("dusunId", event.target.value)}
                aria-label="Filter dusun"
                className="w-full sm:w-40"
              >
                <option value="">Semua dusun</option>
                {dusunOptions.map((item) => (
                  <option key={item.id} value={item.id}>
                    {item.nama}
                  </option>
                ))}
              </Select>
              <Select
                value={filter.rwId}
                onChange={(event) => setValue("rwId", event.target.value)}
                aria-label="Filter RW"
                className="w-full sm:w-32"
              >
                <option value="">Semua RW</option>
                {rwOptions.map((item) => (
                  <option key={item.id} value={item.id}>
                    {item.nama}
                  </option>
                ))}
              </Select>
              <Select
                value={filter.rtId}
                onChange={(event) => setValue("rtId", event.target.value)}
                aria-label="Filter RT"
                className="w-full sm:w-32"
              >
                <option value="">Semua RT</option>
                {rtOptions.map((item) => (
                  <option key={item.id} value={item.id}>
                    {item.nama}
                  </option>
                ))}
              </Select>
              {adaFilter && (
                <Button
                  type="button"
                  variant="ghost"
                  onClick={() => {
                    setSearch("");
                    setQ("");
                    setFilter(emptyFilter);
                    setTanggalFrom("");
                    setTanggalTo("");
                  }}
                >
                  Bersihkan
                </Button>
              )}
            </div>
          </div>

          {spesifik && (
            <div className="grid gap-4 rounded-xl border bg-muted/40 p-4 sm:grid-cols-2 lg:grid-cols-4">
              <div className="space-y-1.5">
                <Label>Jenis Kelamin</Label>
                <Select
                  value={filter.jenisKelamin}
                  onChange={(event) => setValue("jenisKelamin", event.target.value)}
                >
                  <option value="">Laki & perempuan</option>
                  <option value="L">Laki-laki</option>
                  <option value="P">Perempuan</option>
                </Select>
              </div>
              <div className="space-y-1.5">
                <Label>Agama</Label>
                <Select
                  value={filter.agama}
                  onChange={(event) => setValue("agama", event.target.value)}
                >
                  <option value="">Semua agama</option>
                  {AGAMA_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </div>
              <div className="space-y-1.5">
                <Label>Dari tanggal</Label>
                <Input
                  type="date"
                  value={tanggalFrom}
                  onChange={(event) => setTanggalFrom(event.target.value)}
                  aria-label="Dari tanggal"
                />
              </div>
              <div className="space-y-1.5">
                <Label>Sampai tanggal</Label>
                <Input
                  type="date"
                  value={tanggalTo}
                  onChange={(event) => setTanggalTo(event.target.value)}
                  aria-label="Sampai tanggal"
                />
              </div>
            </div>
          )}

          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-16">
                    <div className="flex items-center gap-2">
                      <input
                        type="checkbox"
                        checked={
                          rows.length > 0 &&
                          rows.every((row) => selected.includes(row.id))
                        }
                        onChange={toggleSemua}
                        disabled={!canMutate}
                        aria-label="Pilih semua catatan mutasi"
                      />
                      <span>No</span>
                    </div>
                  </TableHead>
                  {canMutate && <TableHead>Aksi</TableHead>}
                  <TableHead className="w-20">Foto</TableHead>
                  <TableHead>NIK</TableHead>
                  <TableHead>Nama</TableHead>
                  <TableHead className="hidden lg:table-cell">No. KK / Nama KK</TableHead>
                  <TableHead>Jenis Kelamin</TableHead>
                  <TableHead className="hidden xl:table-cell">Dusun</TableHead>
                  <TableHead className="hidden xl:table-cell">RW</TableHead>
                  <TableHead>RT</TableHead>
                  <TableHead>Umur</TableHead>
                  <TableHead>Status Menjadi</TableHead>
                  <TableHead>Tgl Peristiwa</TableHead>
                  <TableHead className="hidden xl:table-cell">Tgl Lapor</TableHead>
                  <TableHead className="hidden lg:table-cell">Asal / Tujuan</TableHead>
                  <TableHead className="hidden lg:table-cell">Alasan</TableHead>
                  <TableHead className="hidden xl:table-cell">Catatan Peristiwa</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {isLoading ? (
                  <TableRow>
                    <TableCell
                      colSpan={canMutate ? 17 : 16}
                      className="py-10 text-center text-muted-foreground"
                    >
                      Memuat data…
                    </TableCell>
                  </TableRow>
                ) : rows.length ? (
                  rows.map((row, index) => {
                    const wilayahRow = rantaiMutasi(row);
                    const keluarga = row.penduduk?.keluarga;
                    return (
                    <TableRow key={row.id}>
                      <TableCell>
                        <div className="flex items-center gap-2">
                          <input
                            type="checkbox"
                            checked={selected.includes(row.id)}
                            onChange={() => toggleSatu(row.id)}
                            disabled={!canMutate}
                            aria-label={`Pilih ${row.nama}`}
                          />
                          <span className="text-xs text-muted-foreground">
                            {index + 1}
                          </span>
                        </div>
                      </TableCell>
                      {canMutate && (
                        <TableCell>
                          <div className="flex gap-1">
                            <Button
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8"
                              aria-label="Ubah"
                              onClick={() => openEdit(row)}
                            >
                              <FilePenLine className="h-4 w-4" />
                            </Button>
                            <Button
                              variant="ghost"
                              size="icon"
                              className="h-8 w-8 text-destructive hover:text-destructive"
                              aria-label="Hapus"
                              onClick={() => setDeleteTarget(row)}
                            >
                              <Trash2 className="h-4 w-4" />
                            </Button>
                          </div>
                        </TableCell>
                      )}
                      <TableCell>
                        <FotoPenduduk
                          pendudukId={row.pendudukId}
                          nama={row.nama}
                          adaFoto={Boolean(row.penduduk?.foto)}
                          versi={row.penduduk?.foto}
                        />
                      </TableCell>
                      <TableCell className="font-mono text-xs">{row.nik ?? "-"}</TableCell>
                      <TableCell className="font-medium">{row.nama}</TableCell>
                      <TableCell className="hidden lg:table-cell">
                        {keluarga ? (
                          <div className="leading-tight">
                            <div className="font-mono text-xs">{keluarga.noKk}</div>
                            <div className="text-xs text-muted-foreground">
                              {keluarga.kepalaKeluarga?.nama ?? "-"}
                            </div>
                          </div>
                        ) : (
                          "-"
                        )}
                      </TableCell>
                      <TableCell>{labelGender(row.penduduk?.jenisKelamin)}</TableCell>
                      <TableCell className="hidden xl:table-cell">
                        {wilayahRow.dusun}
                      </TableCell>
                      <TableCell className="hidden xl:table-cell">{wilayahRow.rw}</TableCell>
                      <TableCell>{wilayahRow.rt}</TableCell>
                      <TableCell>
                        {umurSaatPeristiwa(row.penduduk?.tanggalLahir ?? null, row.tanggal)}
                      </TableCell>
                      <TableCell>
                        <Badge variant={variantJenis(row.jenis)}>
                          {labelJenis(row.jenis)}
                        </Badge>
                      </TableCell>
                      <TableCell className="whitespace-nowrap">
                        {formatDateShort(row.tanggal)}
                      </TableCell>
                      <TableCell className="hidden xl:table-cell whitespace-nowrap text-muted-foreground">
                        {row.createdAt ? formatDateShort(row.createdAt) : "-"}
                      </TableCell>
                      <TableCell className="hidden lg:table-cell max-w-[200px] truncate">
                        {row.asalTujuan ?? "-"}
                      </TableCell>
                      <TableCell className="hidden lg:table-cell max-w-[200px] truncate">
                        {row.alasan ?? "-"}
                      </TableCell>
                      <TableCell className="hidden xl:table-cell max-w-[240px] truncate text-muted-foreground">
                        {row.keterangan ?? "-"}
                      </TableCell>
                    </TableRow>
                    );
                  })
                ) : (
                  <TableRow>
                    <TableCell
                      colSpan={canMutate ? 17 : 16}
                      className="py-12 text-center text-muted-foreground"
                    >
                      {adaFilter
                        ? "Tidak ada catatan mutasi yang cocok dengan filter."
                        : "Belum ada catatan mutasi penduduk."}
                    </TableCell>
                  </TableRow>
                )}
              </TableBody>
            </Table>
          </div>

          {rows.length >= 1000 && (
            <p className="text-xs text-muted-foreground">
              Menampilkan maksimal 1.000 catatan. Persempit filter untuk melihat sisanya.
            </p>
          )}
        </CardContent>
      </Card>

      <Dialog open={formOpen} onOpenChange={setFormOpen}>
        <DialogContent className="max-w-xl">
          <DialogHeader>
            <DialogTitle>{editing ? "Ubah Riwayat Mutasi" : "Catat Mutasi Penduduk"}</DialogTitle>
            <DialogDescription>
              Hubungkan catatan mutasi dengan penduduk agar riwayatnya tampil pada biodata warga.
            </DialogDescription>
          </DialogHeader>

          <form onSubmit={save} className="space-y-4">
            <div className="space-y-1.5">
              <Label>Penduduk</Label>
              <Select
                value={form.pendudukId}
                onChange={(event) => pilihPenduduk(event.target.value)}
              >
                <option value="">Pilih penduduk (opsional)</option>
                {(pendudukList?.data ?? []).map((warga) => (
                  <option key={warga.id} value={warga.id}>
                    {warga.nama} · {warga.nik}
                  </option>
                ))}
              </Select>
            </div>

            <div className="grid gap-4 sm:grid-cols-2">
              <Field label="NIK">
                <Input
                  value={form.nik}
                  onChange={(event) => update("nik", event.target.value)}
                  inputMode="numeric"
                  maxLength={16}
                />
              </Field>
              <Field label="Nama" required>
                <Input
                  required
                  value={form.nama}
                  onChange={(event) => update("nama", event.target.value)}
                />
              </Field>
              <Field label="Status Menjadi" required>
                <Select
                  value={form.jenis}
                  onChange={(event) => update("jenis", event.target.value)}
                >
                  {JENIS_OPTIONS.map((option) => (
                    <option key={option.value} value={option.value}>
                      {option.label}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Tanggal Peristiwa" required>
                <Input
                  required
                  type="date"
                  value={form.tanggal}
                  onChange={(event) => update("tanggal", event.target.value)}
                />
              </Field>
              <Field label="Asal / Tujuan" className="sm:col-span-2">
                <Input
                  value={form.asalTujuan}
                  onChange={(event) => update("asalTujuan", event.target.value)}
                  placeholder="Contoh: Desa Cipari atau Luar negeri"
                />
              </Field>
              <Field label="Alasan" className="sm:col-span-2">
                <Input
                  value={form.alasan}
                  onChange={(event) => update("alasan", event.target.value)}
                />
              </Field>
              <Field label="Catatan Peristiwa" className="sm:col-span-2">
                <Textarea
                  rows={3}
                  value={form.keterangan}
                  onChange={(event) => update("keterangan", event.target.value)}
                />
              </Field>
            </div>

            <DialogFooter>
              <Button type="button" variant="outline" onClick={() => setFormOpen(false)}>
                Batal
              </Button>
              <Button type="submit" disabled={saving}>
                {saving ? "Menyimpan…" : "Simpan"}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>

      <Dialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Hapus catatan mutasi?</DialogTitle>
            <DialogDescription>
              Catatan mutasi <span className="font-semibold">{deleteTarget?.nama}</span>{" "}
              ({deleteTarget ? labelJenis(deleteTarget.jenis) : "-"}) akan dihapus permanen.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setDeleteTarget(null)}>
              Batal
            </Button>
            <Button variant="destructive" onClick={remove} disabled={deleting}>
              {deleting ? "Menghapus…" : "Hapus"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}

function Field({
  label,
  required,
  className,
  children,
}: {
  label: string;
  required?: boolean;
  className?: string;
  children: React.ReactNode;
}) {
  return (
    <div className={`space-y-1.5 ${className ?? ""}`}>
      <Label>
        {label}
        {required && <span className="ml-0.5 text-destructive">*</span>}
      </Label>
      {children}
    </div>
  );
}
