"use client";

import { useRef, useState } from "react";
import useSWR, { useSWRConfig } from "swr";
import { Eraser, Plus, Trash2, Upload, Users } from "lucide-react";
import { toast } from "sonner";
import { apiSend, ApiError, fetcher } from "@/lib/api";
import { unduhCsv } from "@/lib/sekretariat";
import { useSession } from "@/lib/use-session";
import { SimpleCrud, type CrudColumn, type CrudField, type CrudRow } from "@/components/admin/simple-crud";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { formatDateShort } from "@/lib/utils";
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";

const SASARAN_OPTIONS = [
  "Penduduk",
  "Keluarga / KK",
  "Rumah Tangga",
  "Kelompok/Organisasi Kemasyarakatan",
];

const ASAL_DANA_OPTIONS = [
  "Pusat",
  "Provinsi",
  "Kab/Kota",
  "Dana Desa",
  "Lain-lain (Hibah)",
];

const FIELDS: CrudField[] = [
  {
    name: "sasaran",
    label: "Sasaran Program",
    type: "select",
    options: [
      { value: "", label: "Pilih Sasaran Program" },
      ...SASARAN_OPTIONS.map((value) => ({ value, label: value })),
    ],
  },
  { name: "nama", label: "Nama Program", required: true },
  { name: "keterangan", label: "Keterangan", type: "textarea", full: true },
  {
    name: "sumberDana",
    label: "Asal Dana",
    type: "select",
    options: [
      { value: "", label: "Asal Dana" },
      ...ASAL_DANA_OPTIONS.map((value) => ({ value, label: value })),
    ],
  },
  {
    name: "mulai",
    label: "Rentang Waktu Program",
    type: "date",
    placeholder: "Tgl. Mulai",
    defaultValue: new Date().toISOString().slice(0, 10),
  },
  { name: "selesai", label: "Selesai", type: "date", placeholder: "Tgl. Selesai" },
];

function masaBerlaku(row: CrudRow) {
  const mulai = row.mulai ? formatDateShort(String(row.mulai)) : "";
  const selesai = row.selesai ? formatDateShort(String(row.selesai)) : "";
  if (!mulai && !selesai) return "-";
  return `${mulai || "…"} s.d. ${selesai || "…"}`;
}

const COLUMNS: CrudColumn[] = [
  { name: "nama", label: "Nama Program" },
  { name: "sumberDana", label: "Asal Dana", hideOnMobile: true },
  {
    name: "_count",
    label: "Jumlah Peserta",
    render: (row) => {
      const count = row._count as { peserta?: number } | undefined;
      return String(count?.peserta ?? 0);
    },
  },
  { name: "masaBerlaku", label: "Masa Berlaku", hideOnMobile: true, render: masaBerlaku },
  { name: "sasaran", label: "Sasaran" },
  {
    name: "aktif",
    label: "Status",
    render: (row) => (
      <Badge variant={row.aktif ? "success" : "secondary"}>
        {row.aktif ? "Aktif" : "Tidak Aktif"}
      </Badge>
    ),
  },
];

type ImporPeserta = {
  nama: string;
  nik: string;
  alamat: string;
  keterangan: string;
  noKartuPeserta: string;
};

type ImporProgram = {
  nama: string;
  keterangan: string;
  asalDana: string;
  sasaran: string;
  mulai: string;
  selesai: string;
  peserta: ImporPeserta[];
};

const CONTOH_IMPOR_HEADER = [
  "Nama Program",
  "Keterangan",
  "Asal Dana",
  "Sasaran",
  "Mulai",
  "Selesai",
  "NIK Peserta",
  "Nama Peserta",
  "Alamat Peserta",
  "No. Kartu Peserta",
];

function parseImporCsv(text: string): ImporProgram[] {
  const lines = text.replace(/\r/g, "").split("\n").filter((line) => line.trim());
  if (!lines.length) return [];
  const split = (line: string) => {
    const out: string[] = [];
    let current = "";
    let quote = false;
    for (let index = 0; index < line.length; index += 1) {
      const char = line[index];
      if (char === '"') {
        if (quote && line[index + 1] === '"') {
          current += '"';
          index += 1;
        } else {
          quote = !quote;
        }
      } else if (char === "," && !quote) {
        out.push(current);
        current = "";
      } else {
        current += char;
      }
    }
    out.push(current);
    return out.map((value) => value.trim());
  };
  const header = split(lines[0]).map((value) => value.toLowerCase());
  const cell = (cells: string[], name: string) => {
    const index = header.indexOf(name);
    return index >= 0 ? (cells[index] ?? "") : "";
  };

  const program = new Map<string, ImporProgram>();
  for (const line of lines.slice(1)) {
    const cells = split(line);
    const nama = cell(cells, "nama program");
    if (!nama) continue;
    let item = program.get(nama);
    if (!item) {
      item = {
        nama,
        keterangan: cell(cells, "keterangan"),
        asalDana: cell(cells, "asal dana"),
        sasaran: cell(cells, "sasaran"),
        mulai: cell(cells, "mulai"),
        selesai: cell(cells, "selesai"),
        peserta: [],
      };
      program.set(nama, item);
    }
    const namaPeserta = cell(cells, "nama peserta");
    const nik = cell(cells, "nik peserta");
    if (namaPeserta || nik) {
      item.peserta.push({
        nama: namaPeserta,
        nik,
        alamat: cell(cells, "alamat peserta"),
        keterangan: cell(cells, "keterangan peserta"),
        noKartuPeserta: cell(cells, "no. kartu peserta"),
      });
    }
  }
  return Array.from(program.values());
}

interface Peserta {
  id: number;
  programId: number;
  noKartuPeserta: string | null;
  nama: string;
  nik: string | null;
  alamat: string | null;
  keterangan: string | null;
}

function PesertaDialog({ program, onClose }: { program: CrudRow; onClose: () => void }) {
  const { user } = useSession();
  const { mutate: mutateGlobal } = useSWRConfig();
  const programId = Number(program.id);
  const { data, mutate } = useSWR<Peserta[]>(
    `/master/peserta-bantuan?programId=${programId}`,
    fetcher,
  );
  const [form, setForm] = useState({ nama: "", nik: "", alamat: "", noKartuPeserta: "" });
  const [saving, setSaving] = useState(false);

  async function segarkan() {
    await mutate();
    await mutateGlobal("/master/program-bantuan");
  }

  async function add(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setSaving(true);
    try {
      await apiSend("/master/peserta-bantuan", "POST", { ...form, programId });
      toast.success("Peserta ditambahkan");
      setForm({ nama: "", nik: "", alamat: "", noKartuPeserta: "" });
      await segarkan();
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal menambah peserta");
    } finally {
      setSaving(false);
    }
  }

  async function remove(id: number) {
    await apiSend(`/master/peserta-bantuan/${id}`, "DELETE");
    toast.success("Peserta dihapus");
    await segarkan();
  }

  return (
    <Dialog open onOpenChange={(open) => !open && onClose()}>
      <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-3xl">
        <DialogHeader>
          <DialogTitle>Peserta Bantuan</DialogTitle>
          <DialogDescription>{String(program.nama)}</DialogDescription>
        </DialogHeader>

        <div className="overflow-x-auto rounded-lg border border-border">
          <table className="w-full text-sm">
            <thead className="bg-muted/40">
              <tr>
                <th className="px-3 py-2 text-left font-medium">No. Kartu Peserta</th>
                <th className="px-3 py-2 text-left font-medium">Nama</th>
                <th className="px-3 py-2 text-left font-medium">NIK</th>
                <th className="px-3 py-2 text-left font-medium">Alamat</th>
                <th className="w-12" />
              </tr>
            </thead>
            <tbody>
              {(data ?? []).map((peserta) => (
                <tr key={peserta.id} className="border-t border-border">
                  <td className="px-3 py-2">{peserta.noKartuPeserta ?? "-"}</td>
                  <td className="px-3 py-2">{peserta.nama}</td>
                  <td className="px-3 py-2">{peserta.nik ?? "-"}</td>
                  <td className="px-3 py-2">{peserta.alamat ?? "-"}</td>
                  <td className="px-2">
                    {user?.role === "ADMIN" && (
                      <button
                        type="button"
                        onClick={() => remove(peserta.id)}
                        className="rounded p-1 text-muted-foreground hover:bg-destructive/10 hover:text-destructive"
                        aria-label="Hapus peserta"
                      >
                        <Trash2 className="h-4 w-4" />
                      </button>
                    )}
                  </td>
                </tr>
              ))}
              {!data?.length && (
                <tr>
                  <td colSpan={5} className="px-3 py-6 text-center text-muted-foreground">
                    Belum ada peserta.
                  </td>
                </tr>
              )}
            </tbody>
          </table>
        </div>

        {user?.role === "ADMIN" && (
          <form onSubmit={add} className="space-y-3">
            <div className="grid gap-3 sm:grid-cols-2">
              <div className="space-y-1.5">
                <Label htmlFor="peserta-nama">Nama</Label>
                <Input
                  id="peserta-nama"
                  value={form.nama}
                  onChange={(event) => setForm((current) => ({ ...current, nama: event.target.value }))}
                  required
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor="peserta-nik">NIK</Label>
                <Input
                  id="peserta-nik"
                  value={form.nik}
                  onChange={(event) => setForm((current) => ({ ...current, nik: event.target.value }))}
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor="peserta-alamat">Alamat</Label>
                <Input
                  id="peserta-alamat"
                  value={form.alamat}
                  onChange={(event) => setForm((current) => ({ ...current, alamat: event.target.value }))}
                />
              </div>
              <div className="space-y-1.5">
                <Label htmlFor="peserta-kartu">No. Kartu Peserta</Label>
                <Input
                  id="peserta-kartu"
                  value={form.noKartuPeserta}
                  onChange={(event) =>
                    setForm((current) => ({ ...current, noKartuPeserta: event.target.value }))
                  }
                />
              </div>
            </div>
            <DialogFooter>
              <Button type="button" variant="outline" onClick={onClose}>
                Tutup
              </Button>
              <Button type="submit" disabled={saving}>
                <Plus className="h-4 w-4" /> {saving ? "Menyimpan…" : "Tambah Peserta"}
              </Button>
            </DialogFooter>
          </form>
        )}
      </DialogContent>
    </Dialog>
  );
}

export default function BantuanPage() {
  const { user } = useSession();
  const { mutate: mutateGlobal } = useSWRConfig();
  const [program, setProgram] = useState<CrudRow | null>(null);
  const [statusFilter, setStatusFilter] = useState("aktif");
  const [sasaranFilter, setSasaranFilter] = useState("");

  const [imporOpen, setImporOpen] = useState(false);
  const [imporRows, setImporRows] = useState<ImporProgram[]>([]);
  const [imporFileName, setImporFileName] = useState("");
  const [importing, setImporting] = useState(false);
  const [opsi, setOpsi] = useState({
    gantiProgram: false,
    kosongkanPeserta: false,
    gantiPeserta: false,
    acakKartu: true,
  });
  const fileRef = useRef<HTMLInputElement>(null);

  const [bersihOpen, setBersihOpen] = useState(false);
  const [membersihkan, setMembersihkan] = useState(false);

  async function bacaBerkas(event: React.ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file) return;
    const text = await file.text();
    const rows = parseImporCsv(text);
    setImporFileName(file.name);
    setImporRows(rows);
    if (rows.length) {
      toast.success(`${rows.length} program siap diimpor`);
    } else {
      toast.error("Tidak ada baris valid. Periksa judul kolom berkas.");
    }
    if (fileRef.current) fileRef.current.value = "";
  }

  async function impor() {
    if (!imporRows.length) {
      toast.error("Unggah berkas terlebih dahulu");
      return;
    }
    setImporting(true);
    try {
      const hasil = await apiSend<{
        programBaru: number;
        programDiperbarui: number;
        pesertaDitambah: number;
        pesertaDiperbarui: number;
        pesertaDilewati: number;
      }>("/bantuan/impor", "POST", { ...opsi, items: imporRows });
      toast.success(
        `${hasil.programBaru} program baru, ${hasil.pesertaDitambah} peserta ditambahkan` +
          (hasil.pesertaDiperbarui ? `, ${hasil.pesertaDiperbarui} diperbarui` : ""),
      );
      setImporOpen(false);
      setImporRows([]);
      setImporFileName("");
      await mutateGlobal("/master/program-bantuan");
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal mengimpor data");
    } finally {
      setImporting(false);
    }
  }

  async function bersihkan() {
    setMembersihkan(true);
    try {
      const hasil = await apiSend<{ dihapus: number }>("/bantuan/peserta-tidak-valid", "DELETE");
      toast.success(`${hasil.dihapus} peserta tidak valid dibersihkan`);
      setBersihOpen(false);
      await mutateGlobal("/master/program-bantuan");
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal membersihkan data");
    } finally {
      setMembersihkan(false);
    }
  }

  function unduhContoh() {
    unduhCsv("contoh-format-impor-program-bantuan.csv", CONTOH_IMPOR_HEADER, [
      [
        "BLT Dana Desa",
        "Bantuan tunai untuk keluarga prasejahtera",
        "Dana Desa",
        "Keluarga / KK",
        "2026-01-01",
        "2026-12-31",
        "3301010101010001",
        "Budi Santoso",
        "Dusun Krajan",
        "KRT-0001",
      ],
    ]);
  }

  return (
    <>
      <SimpleCrud
        title="Daftar Program Bantuan"
        description="Program bantuan desa beserta daftar penerima manfaat."
        entity="program-bantuan"
        fields={FIELDS}
        columns={COLUMNS}
        searchPlaceholder="Cari program…"
        createLabel="Tambah"
        showNo
        actionOnLeft
        filter={(row) => {
          if (statusFilter === "aktif" && !row.aktif) return false;
          if (statusFilter === "nonaktif" && row.aktif) return false;
          if (sasaranFilter && String(row.sasaran ?? "") !== sasaranFilter) return false;
          return true;
        }}
        ekspor={{
          fileName: "program-bantuan",
          header: ["No", "Nama Program", "Asal Dana", "Jumlah Peserta", "Masa Berlaku", "Sasaran", "Status"],
          values: (row) => [
            "",
            String(row.nama ?? ""),
            String(row.sumberDana ?? ""),
            String((row._count as { peserta?: number } | undefined)?.peserta ?? 0),
            masaBerlaku(row),
            String(row.sasaran ?? ""),
            row.aktif ? "Aktif" : "Tidak Aktif",
          ],
        }}
        rowActions={(row) => (
          <button
            type="button"
            onClick={() => setProgram(row)}
            aria-label="Peserta"
            title="Peserta"
            className="rounded-md p-1.5 text-muted-foreground hover:bg-muted hover:text-foreground"
          >
            <Users className="h-4 w-4" />
          </button>
        )}
        headerExtra={
          user?.role === "ADMIN" && (
            <div className="flex items-center gap-2">
              <Button variant="outline" size="sm" onClick={() => setImporOpen(true)}>
                <Upload className="h-4 w-4" /> Impor
              </Button>
              <Button variant="outline" size="sm" onClick={() => setBersihOpen(true)}>
                <Eraser className="h-4 w-4" /> Bersihkan
              </Button>
            </div>
          )
        }
        toolbar={
          <div className="flex items-center gap-2">
            <Select
              value={statusFilter}
              onChange={(event) => setStatusFilter(event.target.value)}
              className="h-9 w-36"
              aria-label="Filter status"
            >
              <option value="">Semua</option>
              <option value="aktif">Aktif</option>
              <option value="nonaktif">Tidak Aktif</option>
            </Select>
            <Select
              value={sasaranFilter}
              onChange={(event) => setSasaranFilter(event.target.value)}
              className="h-9 w-52"
              aria-label="Filter sasaran"
            >
              <option value="">Pilih Sasaran</option>
              {SASARAN_OPTIONS.map((value) => (
                <option key={value} value={value}>
                  {value}
                </option>
              ))}
            </Select>
          </div>
        }
      />

      {program && <PesertaDialog program={program} onClose={() => setProgram(null)} />}

      <Dialog open={imporOpen} onOpenChange={setImporOpen}>
        <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-lg">
          <DialogHeader>
            <DialogTitle>Impor Program Bantuan</DialogTitle>
            <DialogDescription>
              Unggah berkas CSV berisi program dan pesertanya sekaligus.
            </DialogDescription>
          </DialogHeader>

          <div className="space-y-4">
            <div className="space-y-1.5">
              <Label htmlFor="impor-berkas">Berkas CSV</Label>
              <Input
                id="impor-berkas"
                ref={fileRef}
                type="file"
                accept=".csv,text/csv"
                onChange={bacaBerkas}
              />
              <button
                type="button"
                onClick={unduhContoh}
                className="text-xs text-primary underline-offset-2 hover:underline"
              >
                Contoh Format
              </button>
              {imporFileName && (
                <p className="text-xs text-muted-foreground">
                  {imporFileName} — {imporRows.length} program,{" "}
                  {imporRows.reduce((total, item) => total + item.peserta.length, 0)} peserta
                </p>
              )}
            </div>

            <div className="space-y-2 text-sm">
              <label className="flex items-start gap-2">
                <input
                  type="checkbox"
                  className="mt-0.5"
                  checked={opsi.gantiProgram}
                  onChange={(event) =>
                    setOpsi((current) => ({ ...current, gantiProgram: event.target.checked }))
                  }
                />
                <span>Ganti data program yang sudah ada</span>
              </label>
              <label className="flex items-start gap-2">
                <input
                  type="checkbox"
                  className="mt-0.5"
                  checked={opsi.kosongkanPeserta}
                  onChange={(event) =>
                    setOpsi((current) => ({ ...current, kosongkanPeserta: event.target.checked }))
                  }
                />
                <span>Kosongkan daftar peserta lama setiap program</span>
              </label>
              <label className="flex items-start gap-2">
                <input
                  type="checkbox"
                  className="mt-0.5"
                  checked={opsi.gantiPeserta}
                  onChange={(event) =>
                    setOpsi((current) => ({ ...current, gantiPeserta: event.target.checked }))
                  }
                />
                <span>Ganti data peserta yang sudah ada</span>
              </label>
              <label className="flex items-start gap-2">
                <input
                  type="checkbox"
                  className="mt-0.5"
                  checked={opsi.acakKartu}
                  onChange={(event) =>
                    setOpsi((current) => ({ ...current, acakKartu: event.target.checked }))
                  }
                />
                <span>Buat nomor kartu peserta acak bila kosong</span>
              </label>
            </div>
          </div>

          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setImporOpen(false)}>
              Batal
            </Button>
            <Button type="button" onClick={impor} disabled={importing}>
              <Upload className="h-4 w-4" /> {importing ? "Mengimpor…" : "Impor"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={bersihOpen} onOpenChange={setBersihOpen}>
        <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-md">
          <DialogHeader>
            <DialogTitle>Bersihkan Data Peserta Tidak Valid</DialogTitle>
            <DialogDescription>
              Peserta yang NIK-nya tidak terdaftar di data penduduk akan dihapus dari semua program.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button type="button" variant="outline" onClick={() => setBersihOpen(false)}>
              Batal
            </Button>
            <Button type="button" variant="destructive" onClick={bersihkan} disabled={membersihkan}>
              <Eraser className="h-4 w-4" /> {membersihkan ? "Membersihkan…" : "Bersihkan"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}
