"use client";

import { useEffect, useState } from "react";
import useSWR from "swr";
import {
  ArrowDownAZ,
  Download,
  Eye,
  FilePenLine,
  ImagePlus,
  Plus,
  Printer,
  Search,
  SlidersHorizontal,
  Trash2,
  User,
  UserCheck,
  Users,
  UsersRound,
} from "lucide-react";
import { toast } from "sonner";
import type {
  Desa,
  Keluarga,
  MutasiPenduduk,
  Paginated,
  Penduduk,
  RingkasanPenduduk,
  RumahTangga,
  Wilayah,
} from "@/lib/types";
import { ApiError, apiSend, fetcher } from "@/lib/api";
import { cetakHtml, escapeHtml, kopDesa } from "@/lib/cetak";
import { unduhCsv } from "@/lib/sekretariat";
import { PageHeader, StatCard } from "@/components/page-header";
import { FotoPenduduk } from "@/components/admin/foto-penduduk";
import { Pagination } from "@/components/pagination";
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,
  ASURANSI_OPTIONS,
  BPJS_KETENAGAKERJAAN_OPTIONS,
  CACAT_OPTIONS,
  CARA_KB_OPTIONS,
  GOLONGAN_DARAH_OPTIONS,
  HUBUNGAN_OPTIONS,
  PENDIDIKAN_OPTIONS,
  PENDIDIKAN_SEDANG_OPTIONS,
  PEKERJAAN_OPTIONS,
  PUNYA_TIDAK_OPTIONS,
  SAKIT_MENAHUN_OPTIONS,
  STATUS_KAWIN_OPTIONS,
  STATUS_KTP_OPTIONS,
  formatNumber,
  hitungUmur,
  labelGender,
  labelHubungan,
  labelStatusDasar,
} from "@/lib/utils";

const STATUS_VARIANT: Record<string, "success" | "danger" | "warning" | "secondary"> = {
  HIDUP: "success",
  MATI: "danger",
  PINDAH: "warning",
  HILANG: "secondary",
  PERGI: "warning",
  TIDAK_VALID: "secondary",
};

const WARGANEGARA_OPTIONS = ["WNI", "WNA", "DUA KEWARGANEGARAAN"];

const emptyFilter = {
  status: "",
  statusPenduduk: "",
  jenisKelamin: "",
  dusunId: "",
  rwId: "",
  rtId: "",
  agama: "",
  pendidikan: "",
  pendidikanSedangDitempuh: "",
  pekerjaan: "",
  statusKawin: "",
  golonganDarah: "",
  umurMin: "",
  umurMax: "",
  tanggalLahirMulai: "",
  tanggalLahirSampai: "",
  warganegara: "",
  statusKtp: "",
  cacat: "",
  caraKb: "",
  sakitMenahun: "",
  asuransi: "",
  bpjsKetenagakerjaan: "",
  adat: "",
  suku: "",
  marga: "",
  punyaTagIdCard: "",
  punyaKartuKeluarga: "",
};

type FormState = Record<string, string>;

const emptyForm: FormState = {
  nik: "",
  nama: "",
  jenisKelamin: "L",
  tempatLahir: "",
  tanggalLahir: "",
  agama: "",
  pendidikan: "",
  pekerjaan: "",
  statusKawin: "",
  warganegara: "WNI",
  golonganDarah: "",
  alamat: "",
  statusPenduduk: "TETAP",
  tagIdCard: "",
  tanggalPeristiwa: "",
  rtId: "",
  rumahTanggaId: "",
  keluargaId: "",
  hubunganKeluarga: "",
  statusDasar: "HIDUP",
  telepon: "",
  email: "",
  ayahNama: "",
  ibuNama: "",
  keterangan: "",
  pendidikanSedangDitempuh: "",
  cacat: "",
  sakitMenahun: "",
  caraKb: "",
  statusKtp: "",
  asuransi: "",
  bpjsKetenagakerjaan: "",
  adat: "",
  suku: "",
  marga: "",
  dapatMembacaHuruf: "",
};

function toForm(penduduk: Penduduk): FormState {
  return {
    ...emptyForm,
    nik: penduduk.nik ?? "",
    nama: penduduk.nama ?? "",
    jenisKelamin: penduduk.jenisKelamin,
    tempatLahir: penduduk.tempatLahir ?? "",
    tanggalLahir: penduduk.tanggalLahir ? penduduk.tanggalLahir.slice(0, 10) : "",
    agama: penduduk.agama ?? "",
    pendidikan: penduduk.pendidikan ?? "",
    pekerjaan: penduduk.pekerjaan ?? "",
    statusKawin: penduduk.statusKawin ?? "",
    warganegara: penduduk.warganegara || "WNI",
    golonganDarah: penduduk.golonganDarah ?? "",
    alamat: penduduk.alamat ?? "",
    statusPenduduk: penduduk.statusPenduduk ?? "TETAP",
    tagIdCard: penduduk.tagIdCard ?? "",
    tanggalPeristiwa: penduduk.tanggalPeristiwa
      ? penduduk.tanggalPeristiwa.slice(0, 10)
      : "",
    rtId: penduduk.rtId ? String(penduduk.rtId) : "",
    rumahTanggaId: penduduk.rumahTanggaId ? String(penduduk.rumahTanggaId) : "",
    keluargaId: penduduk.keluargaId ? String(penduduk.keluargaId) : "",
    hubunganKeluarga: penduduk.hubunganKeluarga ?? "",
    statusDasar: penduduk.statusDasar,
    telepon: penduduk.telepon ?? "",
    email: penduduk.email ?? "",
    ayahNama: penduduk.ayahNama ?? "",
    ibuNama: penduduk.ibuNama ?? "",
    keterangan: penduduk.keterangan ?? "",
    pendidikanSedangDitempuh: penduduk.pendidikanSedangDitempuh ?? "",
    cacat: penduduk.cacat ?? "",
    sakitMenahun: penduduk.sakitMenahun ?? "",
    caraKb: penduduk.caraKb ?? "",
    statusKtp: penduduk.statusKtp ?? "",
    asuransi: penduduk.asuransi ?? "",
    bpjsKetenagakerjaan: penduduk.bpjsKetenagakerjaan ?? "",
    adat: penduduk.adat ?? "",
    suku: penduduk.suku ?? "",
    marga: penduduk.marga ?? "",
    dapatMembacaHuruf: penduduk.dapatMembacaHuruf ?? "",
  };
}

// Dikirim walau kosong supaya API menormalkannya menjadi null (field bisa dibersihkan).
const BISA_DIKOSONGKAN = [
  "cacat",
  "caraKb",
  "statusKtp",
  "asuransi",
  "bpjsKetenagakerjaan",
  "sakitMenahun",
  "adat",
  "suku",
  "marga",
  "pendidikanSedangDitempuh",
  "dapatMembacaHuruf",
];

function compact(form: FormState) {
  const payload: Record<string, unknown> = {};
  for (const [key, value] of Object.entries(form)) {
    if (value === "" && !BISA_DIKOSONGKAN.includes(key)) continue;
    payload[key] =
      key === "rtId" || key === "keluargaId" || key === "rumahTanggaId"
        ? Number(value)
        : value;
  }
  return payload;
}

const KOLOM_PENDUDUK_CSV = [
  "NIK",
  "Tag ID Card",
  "Nama",
  "No. KK",
  "Nama Ayah",
  "Nama Ibu",
  "No. Rumah Tangga",
  "Jenis Kelamin",
  "Alamat",
  "Dusun",
  "RW",
  "RT",
  "Pendidikan Dalam KK",
  "Umur",
  "Pekerjaan",
  "Kawin",
  "Tgl Peristiwa",
  "Tgl Terdaftar",
  "Tempat Lahir",
  "Tanggal Lahir",
  "Agama",
  "Golongan Darah",
  "Status Penduduk",
  "Status Dasar",
];

function barisPendudukCsv(row: Penduduk) {
  return [
    row.nik,
    row.tagIdCard ?? "",
    row.nama,
    row.keluarga?.noKk ?? "",
    row.ayahNama ?? "",
    row.ibuNama ?? "",
    row.rumahTangga?.nomor ?? "",
    row.jenisKelamin,
    row.alamat ?? "",
    row.rt?.parent?.parent?.nama ?? "",
    row.rt?.parent?.nama ?? "",
    row.rt?.nama ?? "",
    row.pendidikan ?? "",
    hitungUmur(row.tanggalLahir),
    row.pekerjaan ?? "",
    row.statusKawin ?? "",
    row.tanggalPeristiwa ? row.tanggalPeristiwa.slice(0, 10) : "",
    row.createdAt ? row.createdAt.slice(0, 10) : "",
    row.tempatLahir ?? "",
    row.tanggalLahir ? row.tanggalLahir.slice(0, 10) : "",
    row.agama ?? "",
    row.golonganDarah ?? "",
    row.statusPenduduk === "TIDAK_TETAP" ? "Tidak Tetap" : "Tetap",
    labelStatusDasar(row.statusDasar),
  ];
}

function tanggalPenduduk(value: string | null) {
  return value ? new Date(value).toLocaleDateString("id-ID") : "-";
}

export default function PendudukPage() {
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState("");
  const [q, setQ] = useState("");
  const [filter, setFilter] = useState(emptyFilter);
  const [advancedOpen, setAdvancedOpen] = useState(false);

  const [formOpen, setFormOpen] = useState(false);
  const [editing, setEditing] = useState<Penduduk | null>(null);
  const [form, setForm] = useState<FormState>(emptyForm);
  const [saving, setSaving] = useState(false);
  const [deleteTarget, setDeleteTarget] = useState<Penduduk | null>(null);
  const [deleting, setDeleting] = useState(false);
  const [detailId, setDetailId] = useState<number | null>(null);
  const [exporting, setExporting] = useState(false);
  const [selected, setSelected] = useState<number[]>([]);
  const [aksiTerbuka, setAksiTerbuka] = useState(false);
  const [saringAlamat, setSaringAlamat] = useState({ dusunId: "", rwId: "" });
  const [fotoPilih, setFotoPilih] = useState<string | null>(null);
  const [fotoHapus, setFotoHapus] = useState(false);

  const query = new URLSearchParams({ page: String(page), limit: "10" });
  if (q) query.set("q", q);
  for (const [key, value] of Object.entries(filter)) {
    if (value) query.set(key, value);
  }

  const { data, isLoading, mutate } = useSWR<Paginated<Penduduk>>(
    `/penduduk?${query.toString()}`,
    fetcher,
  );
  const { data: ringkasan, mutate: mutateRingkasan } = useSWR<RingkasanPenduduk>(
    "/penduduk/ringkasan",
    fetcher,
  );
  const { data: wilayah } = useSWR<Wilayah[]>("/wilayah", fetcher);
  const { data: keluargaList } = useSWR<Paginated<Keluarga>>(
    "/keluarga?limit=200",
    fetcher,
  );
  const { data: rumahTanggaList } = useSWR<RumahTangga[]>(
    "/rumah-tangga",
    fetcher,
  );
  const { data: desa } = useSWR<Desa>("/desa", fetcher);
  const { data: detail } = useSWR<Penduduk>(
    detailId ? `/penduduk/${detailId}` : null,
    fetcher,
  );

  const rtOptions = (wilayah ?? []).filter((item) => item.level === "RT");
  const allRegional = wilayah ?? [];
  const dusunOptions = allRegional.filter((item) => item.level === "DUSUN");
  const rwOptions = filter.dusunId
    ? allRegional.filter(
        (item) => item.level === "RW" && item.parentId === Number(filter.dusunId),
      )
    : allRegional.filter((item) => item.level === "RW");
  const rtFiltered = filter.rwId
    ? rtOptions.filter((item) => item.parentId === Number(filter.rwId))
    : rtOptions;
  const rwFormOptions = allRegional.filter(
    (item) =>
      item.level === "RW" &&
      (!saringAlamat.dusunId || item.parentId === Number(saringAlamat.dusunId)),
  );
  const rtFormOptions = rtOptions.filter(
    (item) => !saringAlamat.rwId || item.parentId === Number(saringAlamat.rwId),
  );
  const anggota = data?.data ?? [];
  const filterCount = Object.values(filter).filter(Boolean).length;
  const adaFilter = Boolean(q) || filterCount > 0;

  useEffect(() => {
    setPage(1);
  }, [q, filter]);

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

  function resetFilter() {
    setSearch("");
    setQ("");
    setFilter(emptyFilter);
  }

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

  function pilihRt(id: string) {
    update("rtId", id);
    const rantai = rantaiWilayah(Number(id) || null);
    setSaringAlamat({ dusunId: rantai.dusunId, rwId: rantai.rwId });
  }

  function rantaiWilayah(rtId: number | null) {
    const rt = allRegional.find((item) => item.id === rtId);
    const rw = rt ? allRegional.find((item) => item.id === rt.parentId) : undefined;
    const dusun = rw ? allRegional.find((item) => item.id === rw.parentId) : undefined;
    return {
      dusunId: String(dusun?.id ?? ""),
      rwId: String(rw?.id ?? ""),
      dusun: dusun?.nama ?? "",
      rw: rw?.nama ?? "",
      rt: rt?.nama ?? "",
    };
  }

  function openCreate(preset?: FormState) {
    setEditing(null);
    setForm({ ...emptyForm, ...preset });
    setSaringAlamat({ dusunId: "", rwId: "" });
    setFotoPilih(null);
    setFotoHapus(false);
    setFormOpen(true);
  }

  function buatNikSementara() {
    const contoh = anggota.find((warga) => /^\d{16}$/.test(warga.nik))?.nik;
    const awilayah = (contoh ?? "3303070000000000").slice(0, 6);
    const acak = Array.from({ length: 10 }, () => Math.floor(Math.random() * 10)).join("");
    update("nik", `${awilayah}${acak}`);
    toast.success("NIK sementara dibuat, silakan periksa kembali");
  }

  function openEdit(penduduk: Penduduk) {
    setEditing(penduduk);
    setForm(toForm(penduduk));
    const rantai = rantaiWilayah(penduduk.rtId ?? null);
    setSaringAlamat({ dusunId: rantai.dusunId, rwId: rantai.rwId });
    setFotoPilih(null);
    setFotoHapus(false);
    setFormOpen(true);
  }

  function pilihFoto(event: React.ChangeEvent<HTMLInputElement>) {
    const berkas = event.target.files?.[0];
    event.target.value = "";
    if (!berkas) return;
    if (!/image\/(jpeg|png|webp)/i.test(berkas.type)) {
      toast.error("Foto harus berformat JPG, PNG, atau WEBP");
      return;
    }
    if (berkas.size > 2 * 1024 * 1024) {
      toast.error("Ukuran foto maksimal 2 MB");
      return;
    }
    const pembaca = new FileReader();
    pembaca.onload = () => {
      setFotoPilih(String(pembaca.result));
      setFotoHapus(false);
    };
    pembaca.onerror = () => toast.error("Gagal membaca berkas foto");
    pembaca.readAsDataURL(berkas);
  }

  async function save(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setSaving(true);
    try {
      const payload = compact(form);
      if (fotoPilih) payload.fotoData = fotoPilih;
      else if (fotoHapus) payload.fotoData = "";
      if (editing) {
        for (const key of [
          "rtId",
          "keluargaId",
          "rumahTanggaId",
          "hubunganKeluarga",
          "tanggalLahir",
          "tanggalPeristiwa",
        ]) {
          if (!(key in payload)) payload[key] = null;
        }
        await apiSend(`/penduduk/${editing.id}`, "PATCH", payload);
        toast.success("Data penduduk diperbarui");
      } else {
        await apiSend("/penduduk", "POST", payload);
        toast.success("Penduduk baru ditambahkan");
      }
      setFormOpen(false);
      setEditing(null);
      await mutate();
      await mutateRingkasan();
    } 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(`/penduduk/${deleteTarget.id}`, "DELETE");
      toast.success("Data penduduk dihapus");
      setDeleteTarget(null);
      await mutate();
      await mutateRingkasan();
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal menghapus data");
    } finally {
      setDeleting(false);
    }
  }

  async function ekspor(huruf = false) {
    setExporting(true);
    try {
      const params = new URLSearchParams();
      if (q) params.set("q", q);
      for (const [key, value] of Object.entries(filter)) {
        if (value) params.set(key, value);
      }
      const rows = await fetcher<Penduduk[]>(
        `/penduduk/ekspor?${params.toString()}`,
      );
      if (huruf) rows.sort((a, b) => a.nama.localeCompare(b.nama, "id"));
      unduhCsv(
        `data-penduduk${huruf ? "-huruf" : ""}-${new Date().toISOString().slice(0, 10)}.csv`,
        KOLOM_PENDUDUK_CSV,
        rows.map(barisPendudukCsv),
      );
      toast.success(`${rows.length} data penduduk diekspor`);
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal mengekspor data");
    } finally {
      setExporting(false);
    }
  }

  function toggleSemua() {
    const ids = anggota.map((warga) => warga.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],
    );
  }

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

  function unduhTerpilih() {
    const rows = anggota.filter((warga) => selected.includes(warga.id));
    if (!rows.length) return;
    setAksiTerbuka(false);
    unduhCsv(
      `penduduk-terpilih-${new Date().toISOString().slice(0, 10)}.csv`,
      KOLOM_PENDUDUK_CSV,
      rows.map(barisPendudukCsv),
    );
  }

  function cetakDaftar(rows: Penduduk[], judul = "Daftar Penduduk") {
    if (!rows.length) {
      toast.error("Belum ada data untuk dicetak");
      return;
    }
    const isi = `
      ${kopDesa(desa, judul)}
      <table><thead><tr><th>No</th><th>NIK</th><th>Nama</th><th>JK</th><th>Umur</th><th>Alamat</th><th>RT</th><th>Status</th></tr></thead>
      <tbody>${rows
        .map(
          (row, index) =>
            `<tr><td>${index + 1}</td><td>${escapeHtml(row.nik)}</td><td>${escapeHtml(row.nama)}</td><td>${row.jenisKelamin}</td><td>${hitungUmur(row.tanggalLahir)}</td><td>${escapeHtml(row.alamat ?? "-")}</td><td>${escapeHtml(row.rt?.nama ?? "-")}</td><td>${escapeHtml(labelStatusDasar(row.statusDasar))}</td></tr>`,
        )
        .join("")}</tbody></table>`;
    if (!cetakHtml(judul, isi)) {
      toast.error("Izinkan pop-up untuk mencetak");
    }
  }

  function cetakBiodata() {
    if (!detail) return;
    const rows: [string, string][] = [
      ["NIK", detail.nik],
      ["Tag ID Card", detail.tagIdCard ?? "-"],
      ["Nama Lengkap (Tanpa Gelar)", detail.nama],
      ["Jenis Kelamin", labelGender(detail.jenisKelamin)],
      ["Agama", detail.agama ?? "-"],
      ["Status Penduduk", detail.statusPenduduk === "TIDAK_TETAP" ? "Penduduk Tidak Tetap" : "Penduduk Tetap"],
      ["Status Dasar", labelStatusDasar(detail.statusDasar)],
      ["Hubungan Dalam Keluarga", detail.hubunganKeluarga ? labelHubungan(detail.hubunganKeluarga) : "-"],
      ["Nomor Kartu Keluarga", detail.keluarga?.noKk ?? "-"],
      ["Nomor Rumah Tangga", detail.rumahTangga?.nomor ?? "-"],
      ["Tempat Lahir", detail.tempatLahir ?? "-"],
      ["Tanggal Lahir", detail.tanggalLahir
        ? new Date(detail.tanggalLahir).toLocaleDateString("id-ID", {
            day: "2-digit",
            month: "long",
            year: "numeric",
          })
        : "-"],
      ["Umur", String(hitungUmur(detail.tanggalLahir))],
      ["Pendidikan Dalam KK", detail.pendidikan ?? "-"],
      ["Pekerjaan", detail.pekerjaan ?? "-"],
      ["Golongan Darah", detail.golonganDarah ?? "-"],
      ["Status Warga Negara", detail.warganegara],
      ["Nama Ayah", detail.ayahNama ?? "-"],
      ["Nama Ibu", detail.ibuNama ?? "-"],
      ["Dusun", detail.rt?.parent?.parent?.nama ?? "-"],
      ["RW", detail.rt?.parent?.nama ?? "-"],
      ["RT", detail.rt?.nama ?? "-"],
      ["Alamat Sekarang", detail.alamat ?? "-"],
      ["Nomor Telepon", detail.telepon ?? "-"],
      ["Email", detail.email ?? "-"],
      ["Status Perkawinan", detail.statusKawin ?? "-"],
      ["Tanggal Peristiwa", detail.tanggalPeristiwa
        ? new Date(detail.tanggalPeristiwa).toLocaleDateString("id-ID")
        : "-"],
      ["Keterangan", detail.keterangan ?? "-"],
    ];
    const isi = `
      ${kopDesa(desa, "Biodata Penduduk")}
      <table class="info">
        ${rows
          .map(
            ([label, value]) =>
              `<tr><td>${escapeHtml(label)}</td><td>:</td><td>${escapeHtml(value)}</td></tr>`,
          )
          .join("")}
      </table>
      ${
        detail.mutasi?.length
          ? `<table><thead><tr><th>Tanggal</th><th>Jenis</th><th>Asal / Tujuan</th><th>Keterangan</th></tr></thead><tbody>${detail.mutasi
              .map(
                (item) =>
                  `<tr><td>${escapeHtml(
                    new Date(item.tanggal).toLocaleDateString("id-ID"),
                  )}</td><td>${escapeHtml(item.jenis)}</td><td>${escapeHtml(
                    item.asalTujuan ?? "-",
                  )}</td><td>${escapeHtml(item.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(`Biodata ${detail.nama}`, isi)) {
      toast.error("Izinkan pop-up untuk mencetak biodata");
    }
  }

  return (
    <div className="animate-fade-in space-y-6">
      <PageHeader
        title="Data Penduduk"
        description="Kelola data warga desa, status kependudukan, dan hubungan keluarga."
        action={
          <div className="flex flex-wrap gap-2">
            <Button
              variant="outline"
              onClick={() =>
                openCreate({
                  statusDasar: "HIDUP",
                  tanggalPeristiwa: new Date().toISOString().slice(0, 10),
                })
              }
            >
              <Plus className="h-4 w-4" />
              Penduduk Lahir
            </Button>
            <Button
              variant="outline"
              onClick={() => openCreate({ statusPenduduk: "TIDAK_TETAP" })}
            >
              <Plus className="h-4 w-4" />
              Penduduk Masuk
            </Button>
            <Button variant="outline" onClick={() => cetakDaftar(anggota)}>
              <Printer className="h-4 w-4" />
              Cetak
            </Button>
            <Button variant="outline" onClick={() => ekspor()} disabled={exporting}>
              <Download className="h-4 w-4" />
              {exporting ? "Mengunduh…" : "Unduh"}
            </Button>
            <Button
              variant="outline"
              onClick={() => ekspor(true)}
              disabled={exporting}
              title="Unduh CSV diurutkan berdasarkan nama"
            >
              <ArrowDownAZ className="h-4 w-4" />
              Unduh Huruf
            </Button>
            <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-52 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(
                        anggota.filter((warga) => selected.includes(warga.id)),
                        "Daftar Penduduk Terpilih",
                      );
                    }}
                  >
                    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={unduhTerpilih}
                  >
                    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>
            <Button onClick={() => openCreate()}>
              <Plus className="h-4 w-4" />
              Tambah Penduduk
            </Button>
          </div>
        }
      />

      <div className="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
        <StatCard
          title="Total penduduk"
          value={formatNumber(ringkasan?.total ?? 0)}
          hint="Berstatus hidup"
          icon={Users}
        />
        <StatCard
          title="Laki-laki"
          value={formatNumber(ringkasan?.lakiLaki ?? 0)}
          icon={User}
          tone="sky"
        />
        <StatCard
          title="Perempuan"
          value={formatNumber(ringkasan?.perempuan ?? 0)}
          icon={UserCheck}
          tone="violet"
        />
        <StatCard
          title="Kartu keluarga"
          value={formatNumber(ringkasan?.keluarga ?? 0)}
          icon={UsersRound}
          tone="amber"
        />
      </div>

      <Card>
        <CardContent className="p-0">
          <div className="space-y-3 border-b p-4">
            <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="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, NIK, tag ID, atau alamat…"
                  className="pl-9"
                />
              </form>
              <div className="flex flex-wrap gap-2">
                <Select
                  value={filter.status}
                  onChange={(event) => setValue("status", event.target.value)}
                  aria-label="Filter status dasar"
                  className="w-full sm:w-40"
                >
                  <option value="">Semua status</option>
                  <option value="HIDUP">Hidup</option>
                  <option value="MATI">Meninggal</option>
                  <option value="PINDAH">Pindah</option>
                  <option value="HILANG">Hilang</option>
                  <option value="PERGI">Pergi</option>
                  <option value="TIDAK_VALID">Tidak Valid</option>
                </Select>
                <Select
                  value={filter.statusPenduduk}
                  onChange={(event) => setValue("statusPenduduk", event.target.value)}
                  aria-label="Filter status penduduk"
                  className="w-full sm:w-40"
                >
                  <option value="">Tetap & tidak tetap</option>
                  <option value="TETAP">Penduduk tetap</option>
                  <option value="TIDAK_TETAP">Tidak tetap</option>
                </Select>
                <Select
                  value={filter.jenisKelamin}
                  onChange={(event) => setValue("jenisKelamin", event.target.value)}
                  aria-label="Filter jenis kelamin"
                  className="w-full sm:w-36"
                >
                  <option value="">Laki & perempuan</option>
                  <option value="L">Laki-laki</option>
                  <option value="P">Perempuan</option>
                </Select>
                <Button
                  type="button"
                  variant={advancedOpen ? "default" : "outline"}
                  onClick={() => setAdvancedOpen((open) => !open)}
                >
                  <SlidersHorizontal className="h-4 w-4" />
                  Pencarian Spesifik
                  {filterCount > 0 && (
                    <span className="ml-1 rounded-full bg-white/25 px-1.5 text-xs">
                      {filterCount}
                    </span>
                  )}
                </Button>
                {adaFilter && (
                  <Button type="button" variant="ghost" onClick={resetFilter}>
                    Reset
                  </Button>
                )}
              </div>
            </div>

            {advancedOpen && (
              <div className="grid gap-3 rounded-xl bg-muted/50 p-4 sm:grid-cols-2 lg:grid-cols-4">
                <Field label="Dusun">
                  <Select
                    value={filter.dusunId}
                    onChange={(event) => setValue("dusunId", event.target.value)}
                  >
                    <option value="">Semua dusun</option>
                    {dusunOptions.map((item) => (
                      <option key={item.id} value={item.id}>
                        {item.nama}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="RW">
                  <Select
                    value={filter.rwId}
                    onChange={(event) => setValue("rwId", event.target.value)}
                  >
                    <option value="">Semua RW</option>
                    {rwOptions.map((item) => (
                      <option key={item.id} value={item.id}>
                        {item.nama}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="RT">
                  <Select
                    value={filter.rtId}
                    onChange={(event) => setValue("rtId", event.target.value)}
                  >
                    <option value="">Semua RT</option>
                    {rtFiltered.map((item) => (
                      <option key={item.id} value={item.id}>
                        {item.nama}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="Umur (tahun)">
                  <div className="flex items-center gap-2">
                    <Input
                      type="number"
                      min={0}
                      max={150}
                      value={filter.umurMin}
                      onChange={(event) => setValue("umurMin", event.target.value)}
                      placeholder="Min"
                    />
                    <span className="text-muted-foreground">–</span>
                    <Input
                      type="number"
                      min={0}
                      max={150}
                      value={filter.umurMax}
                      onChange={(event) => setValue("umurMax", event.target.value)}
                      placeholder="Maks"
                    />
                  </div>
                </Field>
                <Field label="Agama">
                  <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>
                </Field>
                <Field label="Pendidikan Dalam KK">
                  <Select
                    value={filter.pendidikan}
                    onChange={(event) => setValue("pendidikan", event.target.value)}
                  >
                    <option value="">Semua pendidikan</option>
                    {PENDIDIKAN_OPTIONS.map((item) => (
                      <option key={item} value={item}>
                        {item}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="Pekerjaan">
                  <Select
                    value={filter.pekerjaan}
                    onChange={(event) => setValue("pekerjaan", event.target.value)}
                  >
                    <option value="">Semua pekerjaan</option>
                    {PEKERJAAN_OPTIONS.map((item) => (
                      <option key={item} value={item}>
                        {item}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="Status Perkawinan">
                  <Select
                    value={filter.statusKawin}
                    onChange={(event) => setValue("statusKawin", event.target.value)}
                  >
                    <option value="">Semua status</option>
                    {STATUS_KAWIN_OPTIONS.map((item) => (
                      <option key={item} value={item}>
                        {item}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="Golongan darah">
                  <Select
                    value={filter.golonganDarah}
                    onChange={(event) => setValue("golonganDarah", event.target.value)}
                  >
                    <option value="">Semua golongan</option>
                    {GOLONGAN_DARAH_OPTIONS.map((item) => (
                      <option key={item} value={item}>
                        {item}
                      </option>
                    ))}
                  </Select>
                </Field>
                <Field label="Pendidikan Sedang Ditempuh">
                  <Pilihan
                    value={filter.pendidikanSedangDitempuh}
                    options={PENDIDIKAN_SEDANG_OPTIONS}
                    placeholder="Semua pendidikan"
                    allowBelum
                    onChange={(value) => setValue("pendidikanSedangDitempuh", value)}
                  />
                </Field>
                <Field label="Tanggal Lahir">
                  <div className="flex items-center gap-2">
                    <Input
                      type="date"
                      value={filter.tanggalLahirMulai}
                      onChange={(event) => setValue("tanggalLahirMulai", event.target.value)}
                      aria-label="Tanggal lahir mulai"
                    />
                    <span className="text-muted-foreground">–</span>
                    <Input
                      type="date"
                      value={filter.tanggalLahirSampai}
                      onChange={(event) => setValue("tanggalLahirSampai", event.target.value)}
                      aria-label="Tanggal lahir sampai"
                    />
                  </div>
                </Field>
                <Field label="Warga Negara">
                  <Pilihan
                    value={filter.warganegara}
                    options={WARGANEGARA_OPTIONS}
                    placeholder="Semua warga negara"
                    onChange={(value) => setValue("warganegara", value)}
                  />
                </Field>
                <Field label="Status KTP">
                  <Pilihan
                    value={filter.statusKtp}
                    options={STATUS_KTP_OPTIONS}
                    placeholder="Semua status KTP"
                    allowBelum
                    onChange={(value) => setValue("statusKtp", value)}
                  />
                </Field>
                <Field label="Cacat">
                  <Pilihan
                    value={filter.cacat}
                    options={CACAT_OPTIONS}
                    placeholder="Semua kondisi"
                    allowBelum
                    onChange={(value) => setValue("cacat", value)}
                  />
                </Field>
                <Field label="Sakit Menahun">
                  <Pilihan
                    value={filter.sakitMenahun}
                    options={SAKIT_MENAHUN_OPTIONS}
                    placeholder="Semua penyakit"
                    allowBelum
                    onChange={(value) => setValue("sakitMenahun", value)}
                  />
                </Field>
                <Field label="Cara KB">
                  <Pilihan
                    value={filter.caraKb}
                    options={CARA_KB_OPTIONS}
                    placeholder="Semua cara KB"
                    allowBelum
                    onChange={(value) => setValue("caraKb", value)}
                  />
                </Field>
                <Field label="Asuransi">
                  <Pilihan
                    value={filter.asuransi}
                    options={ASURANSI_OPTIONS}
                    placeholder="Semua asuransi"
                    allowBelum
                    onChange={(value) => setValue("asuransi", value)}
                  />
                </Field>
                <Field label="Kepemilikan BPJS Ketenagakerjaan">
                  <Pilihan
                    value={filter.bpjsKetenagakerjaan}
                    options={BPJS_KETENAGAKERJAAN_OPTIONS}
                    placeholder="Semua"
                    allowBelum
                    onChange={(value) => setValue("bpjsKetenagakerjaan", value)}
                  />
                </Field>
                <Field label="Kepemilikan Tag ID Card">
                  <Pilihan
                    value={filter.punyaTagIdCard}
                    options={PUNYA_TIDAK_OPTIONS}
                    placeholder="Semua"
                    onChange={(value) => setValue("punyaTagIdCard", value)}
                  />
                </Field>
                <Field label="Kepemilikan Kartu Keluarga">
                  <Pilihan
                    value={filter.punyaKartuKeluarga}
                    options={PUNYA_TIDAK_OPTIONS}
                    placeholder="Semua"
                    onChange={(value) => setValue("punyaKartuKeluarga", value)}
                  />
                </Field>
                <Field label="Adat">
                  <Input
                    value={filter.adat}
                    onChange={(event) => setValue("adat", event.target.value)}
                    placeholder="Cari adat"
                  />
                </Field>
                <Field label="Suku / Etnis">
                  <Input
                    value={filter.suku}
                    onChange={(event) => setValue("suku", event.target.value)}
                    placeholder="Cari suku"
                  />
                </Field>
                <Field label="Marga">
                  <Input
                    value={filter.marga}
                    onChange={(event) => setValue("marga", event.target.value)}
                    placeholder="Cari marga"
                  />
                </Field>
              </div>
            )}
          </div>

          {isLoading ? (
            <div className="space-y-2 p-4">
              {Array.from({ length: 6 }).map((_, index) => (
                <div key={index} className="h-12 animate-pulse rounded-lg bg-muted" />
              ))}
            </div>
          ) : anggota.length ? (
            <Table>
              <TableHeader>
                <TableRow>
                  <TableHead className="w-20">
                    <div className="flex items-center gap-2">
                      <input
                        type="checkbox"
                        checked={
                          anggota.length > 0 &&
                          anggota.every((warga) => selected.includes(warga.id))
                        }
                        onChange={toggleSemua}
                        aria-label="Pilih semua penduduk"
                        className="h-4 w-4 rounded border-input"
                      />
                      <span>No</span>
                    </div>
                  </TableHead>
                  <TableHead className="text-right">Aksi</TableHead>
                  <TableHead className="w-20">Foto</TableHead>
                  <TableHead>NIK</TableHead>
                  <TableHead>Tag ID Card</TableHead>
                  <TableHead>Nama</TableHead>
                  <TableHead>No. KK</TableHead>
                  <TableHead className="hidden lg:table-cell">Nama Ayah</TableHead>
                  <TableHead className="hidden lg:table-cell">Nama Ibu</TableHead>
                  <TableHead>No. Rumah Tangga</TableHead>
                  <TableHead>Jenis Kelamin</TableHead>
                  <TableHead>Alamat</TableHead>
                  <TableHead>Dusun</TableHead>
                  <TableHead>RW</TableHead>
                  <TableHead>RT</TableHead>
                  <TableHead className="hidden xl:table-cell">Pendidikan Dalam KK</TableHead>
                  <TableHead>Umur</TableHead>
                  <TableHead className="hidden xl:table-cell">Pekerjaan</TableHead>
                  <TableHead className="hidden xl:table-cell">Kawin</TableHead>
                  <TableHead className="hidden xl:table-cell">Tgl Peristiwa</TableHead>
                  <TableHead className="hidden xl:table-cell">Tgl Terdaftar</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {anggota.map((warga, index) => (
                  <TableRow key={warga.id}>
                    <TableCell>
                      <div className="flex items-center gap-2">
                        <input
                          type="checkbox"
                          checked={selected.includes(warga.id)}
                          onChange={() => toggleSatu(warga.id)}
                          aria-label={`Pilih ${warga.nama}`}
                          className="h-4 w-4 rounded border-input"
                        />
                        <span className="text-xs text-muted-foreground">{index + 1}</span>
                      </div>
                    </TableCell>
                    <TableCell>
                      <div className="flex gap-1">
                        <Button
                          variant="ghost"
                          size="icon"
                          className="h-8 w-8"
                          onClick={() => setDetailId(warga.id)}
                          aria-label="Lihat detail"
                        >
                          <Eye className="h-4 w-4" />
                        </Button>
                        <Button
                          variant="ghost"
                          size="icon"
                          className="h-8 w-8"
                          onClick={() => openEdit(warga)}
                          aria-label="Ubah data"
                        >
                          <FilePenLine className="h-4 w-4" />
                        </Button>
                        <Button
                          variant="ghost"
                          size="icon"
                          className="h-8 w-8 text-destructive hover:text-destructive"
                          onClick={() => setDeleteTarget(warga)}
                          aria-label="Hapus data"
                        >
                          <Trash2 className="h-4 w-4" />
                        </Button>
                      </div>
                    </TableCell>
                    <TableCell>
                      <FotoPenduduk
                        pendudukId={warga.id}
                        nama={warga.nama}
                        adaFoto={Boolean(warga.foto)}
                        versi={warga.foto}
                      />
                    </TableCell>
                    <TableCell className="font-mono text-xs">
                      {warga.nik}
                    </TableCell>
                    <TableCell className="font-mono text-xs text-muted-foreground">
                      {warga.tagIdCard ?? "-"}
                    </TableCell>
                    <TableCell>
                      <button
                        type="button"
                        onClick={() => setDetailId(warga.id)}
                        className="text-left font-medium hover:text-emerald-700 hover:underline"
                      >
                        {warga.nama}
                      </button>
                      <Badge
                        variant={STATUS_VARIANT[warga.statusDasar] ?? "secondary"}
                        className="ml-2"
                      >
                        {labelStatusDasar(warga.statusDasar)}
                      </Badge>
                    </TableCell>
                    <TableCell className="font-mono text-xs text-muted-foreground">
                      {warga.keluarga?.noKk ?? "-"}
                    </TableCell>
                    <TableCell className="hidden lg:table-cell">
                      {warga.ayahNama ?? "-"}
                    </TableCell>
                    <TableCell className="hidden lg:table-cell">
                      {warga.ibuNama ?? "-"}
                    </TableCell>
                    <TableCell>{warga.rumahTangga?.nomor ?? "-"}</TableCell>
                    <TableCell>{labelGender(warga.jenisKelamin)}</TableCell>
                    <TableCell className="max-w-[200px] truncate">
                      {warga.alamat ?? "-"}
                    </TableCell>
                    <TableCell>{rantaiWilayah(warga.rtId).dusun || "-"}</TableCell>
                    <TableCell>{rantaiWilayah(warga.rtId).rw || "-"}</TableCell>
                    <TableCell>{warga.rt?.nama ?? "-"}</TableCell>
                    <TableCell className="hidden xl:table-cell">
                      {warga.pendidikan ?? "-"}
                    </TableCell>
                    <TableCell>{hitungUmur(warga.tanggalLahir)}</TableCell>
                    <TableCell className="hidden xl:table-cell">
                      {warga.pekerjaan ?? "-"}
                    </TableCell>
                    <TableCell className="hidden xl:table-cell">
                      {warga.statusKawin ?? "-"}
                    </TableCell>
                    <TableCell className="hidden xl:table-cell">
                      {tanggalPenduduk(warga.tanggalPeristiwa)}
                    </TableCell>
                    <TableCell className="hidden xl:table-cell">
                      {tanggalPenduduk(warga.createdAt)}
                    </TableCell>
                  </TableRow>
                ))}
              </TableBody>
            </Table>
          ) : (
            <div className="py-16 text-center">
              <p className="font-semibold">Data tidak ditemukan</p>
              <p className="mt-1 text-sm text-muted-foreground">
                Coba ubah kata kunci pencarian atau tambah penduduk baru.
              </p>
            </div>
          )}

          {data && data.data.length > 0 && (
            <Pagination
              page={data.meta.page}
              totalPages={data.meta.totalPages}
              total={data.meta.total}
              onChange={setPage}
            />
          )}
        </CardContent>
      </Card>

      <Dialog open={formOpen} onOpenChange={setFormOpen}>
        <DialogContent className="max-w-3xl">
          <DialogHeader>
            <DialogTitle>{editing ? "Biodata Penduduk" : "Tambah Penduduk"}</DialogTitle>
            <DialogDescription>
              Isian mengikuti format biodata penduduk OpenSID. Kolom bertanda * wajib diisi.
            </DialogDescription>
          </DialogHeader>

          <form onSubmit={save} className="space-y-5">
            <Section judul="Data Diri">
              <div className="sm:col-span-2">
                <Field label="Foto Penduduk">
                  <div className="flex flex-wrap items-center gap-3">
                    {fotoPilih ? (
                      <img
                        src={fotoPilih}
                        alt="Pratinjau foto baru"
                        className="h-14 w-14 shrink-0 rounded-full object-cover"
                      />
                    ) : (
                      <FotoPenduduk
                        pendudukId={editing?.id ?? null}
                        nama={form.nama || editing?.nama}
                        adaFoto={Boolean(editing?.foto)}
                        versi={editing?.foto}
                      />
                    )}
                    <Input
                      id="penduduk-foto"
                      type="file"
                      accept=".jpg,.jpeg,.png,.webp"
                      onChange={pilihFoto}
                      className="max-w-sm flex-1"
                    />
                    {fotoHapus ? (
                      <Badge variant="warning">Foto akan dihapus</Badge>
                    ) : fotoPilih ? (
                      <Badge variant="info">Foto baru siap disimpan</Badge>
                    ) : null}
                  </div>
                  <p className="text-xs text-muted-foreground">
                    Format JPG, PNG, atau WEBP, maksimal 2 MB. Foto tampil pada kolom
                    Foto di daftar Penduduk, Keluarga, dan Rumah Tangga.
                  </p>
                  {(editing?.foto || fotoPilih) && !fotoHapus && (
                    <Button
                      type="button"
                      variant="outline"
                      size="sm"
                      onClick={() => {
                        setFotoPilih(null);
                        setFotoHapus(true);
                      }}
                    >
                      Hapus foto
                    </Button>
                  )}
                </Field>
              </div>
              <Field label="NIK" required>
                <div className="flex gap-2">
                  <Input
                    required
                    inputMode="numeric"
                    maxLength={16}
                    pattern="\d{16}"
                    title="NIK harus 16 digit angka"
                    value={form.nik}
                    onChange={(event) => update("nik", event.target.value)}
                    placeholder="16 digit NIK"
                    className="flex-1"
                  />
                  <Button
                    type="button"
                    variant="outline"
                    className="shrink-0"
                    onClick={buatNikSementara}
                  >
                    NIK Sementara
                  </Button>
                </div>
              </Field>
              <Field label="Nama Lengkap (Tanpa Gelar)" required>
                <Input
                  required
                  value={form.nama}
                  onChange={(event) => update("nama", event.target.value)}
                  placeholder="Nama sesuai KTP"
                />
              </Field>
              <Field label="Tag ID Card">
                <Input
                  value={form.tagIdCard}
                  onChange={(event) => update("tagIdCard", event.target.value)}
                  placeholder="Contoh: TAG-00021"
                />
              </Field>
              <Field label="Jenis Kelamin" required>
                <Select
                  value={form.jenisKelamin}
                  onChange={(event) => update("jenisKelamin", event.target.value)}
                >
                  <option value="L">Laki-laki</option>
                  <option value="P">Perempuan</option>
                </Select>
              </Field>
              <Field label="Agama">
                <Select
                  value={form.agama}
                  onChange={(event) => update("agama", event.target.value)}
                >
                  <option value="">Pilih agama</option>
                  {AGAMA_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Status Penduduk">
                <Select
                  value={form.statusPenduduk}
                  onChange={(event) => update("statusPenduduk", event.target.value)}
                >
                  <option value="TETAP">Penduduk tetap</option>
                  <option value="TIDAK_TETAP">Penduduk tidak tetap</option>
                </Select>
              </Field>
              <Field label="Status Dasar">
                <Select
                  value={form.statusDasar}
                  onChange={(event) => update("statusDasar", event.target.value)}
                >
                  <option value="HIDUP">Hidup</option>
                  <option value="MATI">Meninggal</option>
                  <option value="PINDAH">Pindah</option>
                  <option value="HILANG">Hilang</option>
                  <option value="PERGI">Pergi</option>
                  <option value="TIDAK_VALID">Tidak Valid</option>
                </Select>
              </Field>
              <Field label="Hubungan Dalam Keluarga">
                <Select
                  value={form.hubunganKeluarga}
                  onChange={(event) => update("hubunganKeluarga", event.target.value)}
                >
                  <option value="">Pilih hubungan</option>
                  {HUBUNGAN_OPTIONS.map((item) => (
                    <option key={item.value} value={item.value}>
                      {item.label}
                    </option>
                  ))}
                </Select>
              </Field>
              <div className="sm:col-span-2">
                <Field label="Keterangan">
                  <Textarea
                    rows={2}
                    value={form.keterangan}
                    onChange={(event) => update("keterangan", event.target.value)}
                  />
                </Field>
              </div>
            </Section>

            <Section judul="Data Kelahiran">
              <Field label="Tempat Lahir">
                <Input
                  value={form.tempatLahir}
                  onChange={(event) => update("tempatLahir", event.target.value)}
                />
              </Field>
              <Field label="Tanggal Lahir">
                <Input
                  type="date"
                  value={form.tanggalLahir}
                  onChange={(event) => update("tanggalLahir", event.target.value)}
                />
              </Field>
              <Field label="Tanggal Peristiwa">
                <Input
                  type="date"
                  value={form.tanggalPeristiwa}
                  onChange={(event) => update("tanggalPeristiwa", event.target.value)}
                />
              </Field>
            </Section>

            <Section judul="Data Pendidikan dan Pekerjaan">
              <Field label="Pendidikan Dalam KK">
                <Select
                  value={form.pendidikan}
                  onChange={(event) => update("pendidikan", event.target.value)}
                >
                  <option value="">Pilih pendidikan</option>
                  {PENDIDIKAN_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Pekerjaan">
                <Select
                  value={form.pekerjaan}
                  onChange={(event) => update("pekerjaan", event.target.value)}
                >
                  <option value="">Pilih pekerjaan</option>
                  {PEKERJAAN_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Pendidikan Sedang Ditempuh">
                <Pilihan
                  value={form.pendidikanSedangDitempuh}
                  options={PENDIDIKAN_SEDANG_OPTIONS}
                  placeholder="Pilih pendidikan sedang ditempuh"
                  onChange={(value) => update("pendidikanSedangDitempuh", value)}
                />
              </Field>
              <Field label="Dapat Membaca Huruf">
                <Select
                  value={form.dapatMembacaHuruf}
                  onChange={(event) => update("dapatMembacaHuruf", event.target.value)}
                >
                  <option value="">Pilih</option>
                  <option value="Ya">Ya</option>
                  <option value="Tidak">Tidak</option>
                  <option value="Belum">Belum</option>
                </Select>
              </Field>
            </Section>

            <Section judul="Data Kesehatan">
              <Field label="Golongan Darah">
                <Select
                  value={form.golonganDarah}
                  onChange={(event) => update("golonganDarah", event.target.value)}
                >
                  <option value="">Pilih</option>
                  {GOLONGAN_DARAH_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Cacat">
                <Pilihan
                  value={form.cacat}
                  options={CACAT_OPTIONS}
                  placeholder="Pilih jenis cacat"
                  onChange={(value) => update("cacat", value)}
                />
              </Field>
              <Field label="Sakit Menahun">
                <Pilihan
                  value={form.sakitMenahun}
                  options={SAKIT_MENAHUN_OPTIONS}
                  placeholder="Pilih sakit menahun"
                  onChange={(value) => update("sakitMenahun", value)}
                />
              </Field>
              <Field label="Cara KB">
                <Pilihan
                  value={form.caraKb}
                  options={CARA_KB_OPTIONS}
                  placeholder="Pilih cara KB"
                  onChange={(value) => update("caraKb", value)}
                />
              </Field>
            </Section>

            <Section judul="Data Identitas dan Jaminan">
              <Field label="Status KTP">
                <Pilihan
                  value={form.statusKtp}
                  options={STATUS_KTP_OPTIONS}
                  placeholder="Pilih status KTP"
                  onChange={(value) => update("statusKtp", value)}
                />
              </Field>
              <Field label="Asuransi">
                <Pilihan
                  value={form.asuransi}
                  options={ASURANSI_OPTIONS}
                  placeholder="Pilih asuransi"
                  onChange={(value) => update("asuransi", value)}
                />
              </Field>
              <Field label="Kepemilikan BPJS Ketenagakerjaan">
                <Pilihan
                  value={form.bpjsKetenagakerjaan}
                  options={BPJS_KETENAGAKERJAAN_OPTIONS}
                  placeholder="Pilih"
                  onChange={(value) => update("bpjsKetenagakerjaan", value)}
                />
              </Field>
            </Section>

            <Section judul="Data Sosial Budaya">
              <Field label="Adat">
                <Input
                  value={form.adat}
                  onChange={(event) => update("adat", event.target.value)}
                  placeholder="Contoh: Sunda, Jawa, Batak"
                />
              </Field>
              <Field label="Suku / Etnis">
                <Input
                  value={form.suku}
                  onChange={(event) => update("suku", event.target.value)}
                  placeholder="Contoh: Sunda"
                />
              </Field>
              <Field label="Marga">
                <Input
                  value={form.marga}
                  onChange={(event) => update("marga", event.target.value)}
                  placeholder="Contoh: Naibahu"
                />
              </Field>
            </Section>

            <Section judul="Data Kewarganegaraan">
              <Field label="Status Warga Negara">
                <Select
                  value={form.warganegara}
                  onChange={(event) => update("warganegara", event.target.value)}
                >
                  {WARGANEGARA_OPTIONS.includes(form.warganegara) ? null : (
                    <option value={form.warganegara}>{form.warganegara}</option>
                  )}
                  {WARGANEGARA_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </Field>
            </Section>

            <Section judul="Data Orang Tua">
              <Field label="Nama Ayah">
                <Input
                  value={form.ayahNama}
                  onChange={(event) => update("ayahNama", event.target.value)}
                />
              </Field>
              <Field label="Nama Ibu">
                <Input
                  value={form.ibuNama}
                  onChange={(event) => update("ibuNama", event.target.value)}
                />
              </Field>
            </Section>

            <Section judul="Data Alamat">
              <Field label="Dusun">
                <Select
                  value={saringAlamat.dusunId}
                  onChange={(event) => {
                    setSaringAlamat({ dusunId: event.target.value, rwId: "" });
                    update("rtId", "");
                  }}
                >
                  <option value="">Pilih dusun</option>
                  {dusunOptions.map((item) => (
                    <option key={item.id} value={item.id}>
                      {item.nama}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="RW">
                <Select
                  value={saringAlamat.rwId}
                  onChange={(event) => {
                    setSaringAlamat((current) => ({ ...current, rwId: event.target.value }));
                    update("rtId", "");
                  }}
                >
                  <option value="">Pilih RW</option>
                  {rwFormOptions.map((item) => (
                    <option key={item.id} value={item.id}>
                      {item.nama}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="RT">
                <Select value={form.rtId} onChange={(event) => pilihRt(event.target.value)}>
                  <option value="">Pilih RT</option>
                  {rtFormOptions.map((item) => (
                    <option key={item.id} value={item.id}>
                      {item.nama}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Alamat Sekarang">
                <Input
                  value={form.alamat}
                  onChange={(event) => update("alamat", event.target.value)}
                  placeholder="Jalan, dusun, nomor rumah"
                />
              </Field>
              <Field label="Nomor Telepon">
                <Input
                  value={form.telepon}
                  onChange={(event) => update("telepon", event.target.value)}
                />
              </Field>
              <Field label="Email">
                <Input
                  type="email"
                  value={form.email}
                  onChange={(event) => update("email", event.target.value)}
                />
              </Field>
            </Section>

            <Section judul="Data Keluarga">
              <Field label="Nomor Kartu Keluarga">
                <Select
                  value={form.keluargaId}
                  onChange={(event) => update("keluargaId", event.target.value)}
                >
                  <option value="">Tidak terhubung</option>
                  {(keluargaList?.data ?? []).map((kk) => (
                    <option key={kk.id} value={kk.id}>
                      {kk.noKk} · {kk.kepalaKeluarga?.nama ?? "-"}
                    </option>
                  ))}
                </Select>
              </Field>
              <Field label="Nomor Rumah Tangga">
                <Select
                  value={form.rumahTanggaId}
                  onChange={(event) => update("rumahTanggaId", event.target.value)}
                >
                  <option value="">Tidak terhubung</option>
                  {(rumahTanggaList ?? []).map((rtm) => (
                    <option key={rtm.id} value={rtm.id}>
                      {rtm.nomor} · {rtm.kepalaNama}
                    </option>
                  ))}
                </Select>
              </Field>
            </Section>

            <Section judul="Data Perkawinan">
              <Field label="Status Perkawinan">
                <Select
                  value={form.statusKawin}
                  onChange={(event) => update("statusKawin", event.target.value)}
                >
                  <option value="">Pilih status</option>
                  {STATUS_KAWIN_OPTIONS.map((item) => (
                    <option key={item} value={item}>
                      {item}
                    </option>
                  ))}
                </Select>
              </Field>
            </Section>

            <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={detailId !== null}
        onOpenChange={(open) => !open && setDetailId(null)}
      >
        <DialogContent className="max-w-3xl">
          <DialogHeader>
            <DialogTitle>Detail Penduduk</DialogTitle>
            <DialogDescription>
              Biodata lengkap, keanggotaan keluarga/rumah tangga/kelompok, dan riwayat mutasi.
            </DialogDescription>
          </DialogHeader>

          {!detail ? (
            <div className="space-y-2">
              {Array.from({ length: 5 }).map((_, index) => (
                <div key={index} className="h-8 animate-pulse rounded bg-muted" />
              ))}
            </div>
          ) : (
            <div className="-mx-1 max-h-[65vh] space-y-5 overflow-y-auto px-1">
              <div className="flex flex-wrap items-center gap-3">
                <FotoPenduduk
                  pendudukId={detail.id}
                  nama={detail.nama}
                  adaFoto={Boolean(detail.foto)}
                  versi={detail.foto}
                />
                <div className="flex flex-wrap items-center gap-2">
                  <div className="text-lg font-semibold">{detail.nama}</div>
                <Badge variant={STATUS_VARIANT[detail.statusDasar] ?? "secondary"}>
                  {labelStatusDasar(detail.statusDasar)}
                </Badge>
                <Badge variant={detail.statusPenduduk === "TIDAK_TETAP" ? "warning" : "success"}>
                  {detail.statusPenduduk === "TIDAK_TETAP" ? "Tidak tetap" : "Tetap"}
                </Badge>
                {detail.tagIdCard && (
                  <span className="font-mono text-xs text-muted-foreground">
                    {detail.tagIdCard}
                  </span>
                )}
                </div>
              </div>

              <section>
                <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Data Diri
                </div>
                <div className="grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2">
                  <DetailRow label="NIK" value={detail.nik} mono />
                  <DetailRow label="Tag ID Card" value={detail.tagIdCard ?? "-"} mono />
                  <DetailRow label="Nama Lengkap (Tanpa Gelar)" value={detail.nama} />
                  <DetailRow label="Jenis Kelamin" value={labelGender(detail.jenisKelamin)} />
                  <DetailRow label="Agama" value={detail.agama ?? "-"} />
                  <DetailRow label="Status Penduduk" value={detail.statusPenduduk === "TIDAK_TETAP" ? "Penduduk Tidak Tetap" : "Penduduk Tetap"} />
                  <DetailRow label="Status Dasar" value={labelStatusDasar(detail.statusDasar)} />
                  <DetailRow label="Pendidikan Dalam KK" value={detail.pendidikan ?? "-"} />
                  <DetailRow label="Pekerjaan" value={detail.pekerjaan ?? "-"} />
                  <DetailRow label="Status Perkawinan" value={detail.statusKawin ?? "-"} />
                  <DetailRow label="Status Warga Negara" value={detail.warganegara} />
                  <DetailRow label="Golongan Darah" value={detail.golonganDarah ?? "-"} />
                  <DetailRow label="Nama Ayah" value={detail.ayahNama ?? "-"} />
                  <DetailRow label="Nama Ibu" value={detail.ibuNama ?? "-"} />
                  <DetailRow label="Nomor Telepon" value={detail.telepon ?? "-"} />
                  <DetailRow label="Email" value={detail.email ?? "-"} />
                </div>
              </section>

              <section>
                <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Atribut Tambahan
                </div>
                <div className="grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2">
                  <DetailRow
                    label="Pendidikan Sedang Ditempuh"
                    value={detail.pendidikanSedangDitempuh ?? "-"}
                  />
                  <DetailRow label="Cacat" value={detail.cacat ?? "-"} />
                  <DetailRow label="Sakit Menahun" value={detail.sakitMenahun ?? "-"} />
                  <DetailRow label="Cara KB" value={detail.caraKb ?? "-"} />
                  <DetailRow label="Status KTP" value={detail.statusKtp ?? "-"} />
                  <DetailRow label="Asuransi" value={detail.asuransi ?? "-"} />
                  <DetailRow
                    label="Kepemilikan BPJS Ketenagakerjaan"
                    value={detail.bpjsKetenagakerjaan ?? "-"}
                  />
                  <DetailRow label="Adat" value={detail.adat ?? "-"} />
                  <DetailRow label="Suku / Etnis" value={detail.suku ?? "-"} />
                  <DetailRow label="Marga" value={detail.marga ?? "-"} />
                </div>
              </section>

              <section>
                <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Data Kelahiran & Peristiwa
                </div>
                <div className="grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2">
                  <DetailRow label="Tempat Lahir" value={detail.tempatLahir ?? "-"} />
                  <DetailRow
                    label="Tanggal Lahir"
                    value={
                      detail.tanggalLahir
                        ? new Date(detail.tanggalLahir).toLocaleDateString("id-ID", {
                            day: "2-digit",
                            month: "long",
                            year: "numeric",
                          })
                        : "-"
                    }
                  />
                  <DetailRow label="Umur" value={hitungUmur(detail.tanggalLahir)} />
                  <DetailRow
                    label="Tanggal Peristiwa"
                    value={
                      detail.tanggalPeristiwa
                        ? new Date(detail.tanggalPeristiwa).toLocaleDateString("id-ID")
                        : "-"
                    }
                  />
                  <DetailRow label="Alamat Sekarang" value={detail.alamat ?? "-"} />
                  <DetailRow label="Dusun" value={detail.rt?.parent?.parent?.nama ?? "-"} />
                  <DetailRow label="RW" value={detail.rt?.parent?.nama ?? "-"} />
                </div>
              </section>

              <section>
                <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Data Keluarga
                </div>
                <div className="grid gap-x-6 gap-y-2 text-sm sm:grid-cols-2">
                  <DetailRow label="Nomor Kartu Keluarga" value={detail.keluarga?.noKk ?? "-"} mono />
                  <DetailRow
                    label="Hubungan Dalam Keluarga"
                    value={labelHubungan(detail.hubunganKeluarga)}
                  />
                  <DetailRow
                    label="Nomor Rumah Tangga"
                    value={detail.rumahTangga?.nomor ?? "-"}
                    mono
                  />
                  <DetailRow label="RT" value={detail.rt?.nama ?? "-"} />
                </div>
              </section>

              <section>
                <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Keanggotaan Kelompok
                </div>
                {detail.kelompokAnggota?.length ? (
                  <div className="flex flex-wrap gap-2">
                    {detail.kelompokAnggota.map((item) => (
                      <span
                        key={item.id}
                        className="rounded-full border bg-muted/50 px-3 py-1 text-xs"
                      >
                        {item.kelompok.nama}
                        {item.jabatan ? (
                          <span className="text-muted-foreground"> · {item.jabatan}</span>
                        ) : null}
                      </span>
                    ))}
                  </div>
                ) : (
                  <p className="text-sm text-muted-foreground">Belum tergabung dalam kelompok.</p>
                )}
              </section>

              <section>
                <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                  Riwayat Mutasi
                </div>
                {detail.mutasi?.length ? (
                  <div className="overflow-hidden rounded-lg border">
                    <Table>
                      <TableHeader>
                        <TableRow>
                          <TableHead>Tanggal</TableHead>
                          <TableHead>Jenis</TableHead>
                          <TableHead>Asal / Tujuan</TableHead>
                          <TableHead>Keterangan</TableHead>
                        </TableRow>
                      </TableHeader>
                      <TableBody>
                        {detail.mutasi.map((item) => (
                          <TableRow key={item.id}>
                            <TableCell className="whitespace-nowrap text-xs">
                              {new Date(item.tanggal).toLocaleDateString("id-ID")}
                            </TableCell>
                            <TableCell>
                              <Badge variant="secondary">{item.jenis}</Badge>
                            </TableCell>
                            <TableCell className="text-xs">{item.asalTujuan ?? "-"}</TableCell>
                            <TableCell className="text-xs">{item.keterangan ?? "-"}</TableCell>
                          </TableRow>
                        ))}
                      </TableBody>
                    </Table>
                  </div>
                ) : (
                  <p className="text-sm text-muted-foreground">Belum ada riwayat mutasi.</p>
                )}
              </section>

              {detail.keterangan && (
                <section>
                  <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
                    Keterangan
                  </div>
                  <p className="text-sm">{detail.keterangan}</p>
                </section>
              )}
            </div>
          )}

          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setDetailId(null)}>
              Kembali Ke Daftar Penduduk
            </Button>
            <Button
              type="button"
              variant="outline"
              disabled={!detail}
              onClick={() => {
                if (!detail) return;
                const sumber = anggota.find((warga) => warga.id === detail.id) ?? detail;
                setDetailId(null);
                openEdit(sumber);
              }}
            >
              <FilePenLine className="h-4 w-4" />
              Ubah
            </Button>
            <Button type="button" onClick={cetakBiodata} disabled={!detail}>
              <Printer className="h-4 w-4" />
              Cetak Biodata
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={!!deleteTarget} onOpenChange={(open) => !open && setDeleteTarget(null)}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Hapus data penduduk?</DialogTitle>
            <DialogDescription>
              Data <span className="font-semibold">{deleteTarget?.nama}</span> akan dihapus
              permanen. Data yang memiliki permohonan surat tidak dapat dihapus.
            </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 Section({
  judul,
  children,
}: {
  judul: string;
  children: React.ReactNode;
}) {
  return (
    <div>
      <div className="mb-3 border-b pb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
        {judul}
      </div>
      <div className="grid gap-4 sm:grid-cols-2">{children}</div>
    </div>
  );
}

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

function Pilihan({
  value,
  options,
  placeholder,
  onChange,
  allowBelum,
}: {
  value: string;
  options: string[];
  placeholder: string;
  onChange: (value: string) => void;
  allowBelum?: boolean;
}) {
  return (
    <Select value={value} onChange={(event) => onChange(event.target.value)}>
      <option value="">{placeholder}</option>
      {allowBelum ? <option value="BELUM">Belum diisi</option> : null}
      {value && !options.includes(value) && value !== "BELUM" ? (
        <option value={value}>{value}</option>
      ) : null}
      {options.map((item) => (
        <option key={item} value={item}>
          {item}
        </option>
      ))}
    </Select>
  );
}

function DetailRow({
  label,
  value,
  mono,
}: {
  label: string;
  value: React.ReactNode;
  mono?: boolean;
}) {
  return (
    <div className="flex gap-2">
      <span className="w-52 shrink-0 text-muted-foreground">{label}</span>
      <span className={mono ? "font-mono text-xs" : ""}>{value}</span>
    </div>
  );
}
