"use client";

import { useEffect, useMemo, useState } from "react";
import useSWR from "swr";
import {
  FileUp,
  FolderOpen,
  Pencil,
  Printer,
  Trash2,
} from "lucide-react";
import { toast } from "sonner";
import type { LaporanApbdes, TahunAnggaran } from "@/lib/types";
import { ApiError, apiSend, fetcher } from "@/lib/api";
import { useSession } from "@/lib/use-session";
import { PageHeader } from "@/components/page-header";
import { KeuanganTabs } from "@/components/admin/keuangan-tabs";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } 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 { formatDate } from "@/lib/utils";

const MAX_UKURAN = 8 * 1024 * 1024;

function ukuranFile(bytes: number) {
  if (bytes >= 1024 * 1024) {
    return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
  }
  return `${Math.max(1, Math.round(bytes / 1024))} KB`;
}

function semesters(tahun: number) {
  return [
    `Laporan APBDes Semester 1 Tahun ${tahun}`,
    `Laporan APBDes Semester 2 Tahun ${tahun}`,
  ];
}

export default function KeuanganLaporanApbdesPage() {
  const { user } = useSession();
  const isAdmin = user?.role === "ADMIN";

  const { data: list, isLoading, mutate } = useSWR<LaporanApbdes[]>(
    "/keuangan/apbdes",
    fetcher,
  );
  const { data: tahunList } = useSWR<TahunAnggaran[]>("/keuangan/tahun", fetcher);

  const [open, setOpen] = useState(false);
  const [editing, setEditing] = useState<LaporanApbdes | null>(null);
  const [tahun, setTahun] = useState(String(new Date().getFullYear()));
  const [semester, setSemester] = useState("1");
  const [judul, setJudul] = useState("");
  const [satuan, setSatuan] = useState("");
  const [keterangan, setKeterangan] = useState("");
  const [berkas, setBerkas] = useState<{ nama: string; dataUrl: string; ukuran: number } | null>(null);
  const [saving, setSaving] = useState(false);

  const [filterTahun, setFilterTahun] = useState("");
  const [selected, setSelected] = useState<number[]>([]);
  const [deleteTarget, setDeleteTarget] = useState<LaporanApbdes | null>(null);
  const [bulkOpen, setBulkOpen] = useState(false);
  const [deleting, setDeleting] = useState(false);

  const opsiTahun = useMemo(() => {
    const daftar = (tahunList ?? []).map((item) => item.tahun);
    const dariLaporan = (list ?? []).map((item) => item.tahun);
    return [...new Set([...daftar, ...dariLaporan])].sort((a, b) => b - a);
  }, [tahunList, list]);

  const rows = useMemo(() => {
    const data = list ?? [];
    return filterTahun
      ? data.filter((item) => String(item.tahun) === filterTahun)
      : data;
  }, [list, filterTahun]);

  const terpilih = useMemo(
    () => rows.filter((row) => selected.includes(row.id)),
    [rows, selected],
  );

  useEffect(() => {
    if (!opsiTahun.length) return;
    if (!opsiTahun.includes(Number(tahun))) setTahun(String(opsiTahun[0]));
  }, [opsiTahun, tahun]);

  function bukaBaru() {
    const aktif = tahunList?.find((item) => item.status === "AKTIF");
    const tahunAwal = aktif?.tahun ?? opsiTahun[0] ?? new Date().getFullYear();
    setEditing(null);
    setTahun(String(tahunAwal));
    setSemester("1");
    setJudul(semesters(tahunAwal)[0]);
    setSatuan("");
    setKeterangan("");
    setBerkas(null);
    setOpen(true);
  }

  function bukaEdit(row: LaporanApbdes) {
    setEditing(row);
    setTahun(String(row.tahun));
    setSemester(String(row.semester));
    setJudul(row.judul);
    setSatuan(row.satuan ?? "");
    setKeterangan(row.keterangan ?? "");
    setBerkas(null);
    setOpen(true);
  }

  function pilihTahun(value: string) {
    setTahun(value);
    if (!editing) {
      const nomor = Number(value);
      setJudul(semesters(nomor)[Number(semester) - 1]);
    }
  }

  function pilihSemester(value: string) {
    setSemester(value);
    if (!editing) {
      setJudul(semesters(Number(tahun))[Number(value) - 1]);
    }
  }

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

  function toggleSemua() {
    const semuaIds = rows.map((row) => row.id);
    const sudah =
      semuaIds.length > 0 && semuaIds.every((id) => selected.includes(id));
    setSelected((current) =>
      sudah
        ? current.filter((id) => !semuaIds.includes(id))
        : [...new Set([...current, ...semuaIds])],
    );
  }

  async function pilihBerkas(event: React.ChangeEvent<HTMLInputElement>) {
    const file = event.target.files?.[0];
    if (!file) return;
    if (file.type !== "application/pdf" && !file.name.toLowerCase().endsWith(".pdf")) {
      toast.error("Berkas laporan harus berupa PDF");
      return;
    }
    if (file.size > MAX_UKURAN) {
      toast.error("Ukuran berkas maksimal 8 MB");
      return;
    }
    const dataUrl = await new Promise<string>((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(String(reader.result));
      reader.onerror = () => reject(reader.error);
      reader.readAsDataURL(file);
    }).catch(() => "");
    if (!dataUrl) {
      toast.error("Gagal membaca berkas");
      return;
    }
    setBerkas({ nama: file.name, dataUrl, ukuran: file.size });
  }

  async function simpan(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!berkas && !editing) {
      toast.error("Unggah berkas laporan PDF terlebih dahulu");
      return;
    }
    setSaving(true);
    try {
      await apiSend("/keuangan/apbdes", "POST", {
        tahun: Number(tahun),
        semester: Number(semester),
        judul,
        ...(satuan ? { satuan } : {}),
        ...(keterangan ? { keterangan } : {}),
        ...(berkas
          ? { namaFile: berkas.nama, dataUrl: berkas.dataUrl }
          : {}),
      });
      toast.success(
        editing
          ? "Laporan APBDes diperbarui"
          : "Laporan APBDes tersimpan",
      );
      setOpen(false);
      await mutate();
    } catch (error) {
      toast.error(
        error instanceof ApiError ? error.message : "Gagal menyimpan laporan APBDes",
      );
    } finally {
      setSaving(false);
    }
  }

  async function hapus() {
    if (!deleteTarget) return;
    setDeleting(true);
    try {
      await apiSend(`/keuangan/apbdes/${deleteTarget.id}`, "DELETE");
      toast.success("Laporan APBDes dihapus");
      const id = deleteTarget.id;
      setSelected((current) => current.filter((item) => item !== id));
      setDeleteTarget(null);
      await mutate();
    } catch (error) {
      toast.error(
        error instanceof ApiError ? error.message : "Gagal menghapus laporan",
      );
    } finally {
      setDeleting(false);
    }
  }

  async function hapusTerpilih() {
    const jumlah = terpilih.length;
    setDeleting(true);
    const hasil = await Promise.allSettled(
      terpilih.map((row) => apiSend(`/keuangan/apbdes/${row.id}`, "DELETE")),
    );
    const gagal = hasil.filter((item) => item.status === "rejected").length;
    setDeleting(false);
    setBulkOpen(false);
    setSelected([]);
    await mutate();
    if (gagal) toast.error(`${gagal} dari ${jumlah} laporan gagal dihapus`);
    else toast.success(`${jumlah} laporan dihapus`);
  }

  const semuaTerpilih =
    rows.length > 0 && rows.every((row) => selected.includes(row.id));
  const kolom = isAdmin ? 9 : 8;

  return (
    <div className="animate-fade-in space-y-6">
      <PageHeader
        title="Laporan APBDes"
        description="Arsip laporan realisasi pelaksanaan APBDes per semester dalam bentuk PDF."
        action={
          isAdmin ? (
            <Button onClick={bukaBaru}>
              <FileUp className="h-4 w-4" />
              Tambah
            </Button>
          ) : undefined
        }
      />

      <KeuanganTabs />

      <div className="hidden print:block">
        <h1 className="text-center text-lg font-bold uppercase">
          Pemerintah Desa Mulyadadi
        </h1>
        <p className="text-center text-sm">
          Kecamatan Cipari, Kabupaten Cilacap
        </p>
        <h2 className="mt-4 text-center text-base font-semibold">
          Daftar Laporan APBDes
        </h2>
      </div>

      <Card>
        <CardHeader className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
          <CardTitle>Arsip laporan</CardTitle>
          <div className="flex flex-wrap items-center gap-2 print:hidden">
            <Select
              value={filterTahun}
              onChange={(event) => setFilterTahun(event.target.value)}
              className="w-40"
              aria-label="Pilih tahun laporan"
            >
              <option value="">Pilih Tahun</option>
              {opsiTahun.map((nomor) => (
                <option key={nomor} value={nomor}>
                  {nomor}
                </option>
              ))}
            </Select>
            {isAdmin && (
              <>
                <Button
                  variant="outline"
                  onClick={() => setBulkOpen(true)}
                  disabled={!terpilih.length}
                >
                  <Trash2 className="h-4 w-4" />
                  Hapus
                </Button>
              </>
            )}
            <Button variant="outline" onClick={() => window.print()}>
              <Printer className="h-4 w-4" />
              Cetak
            </Button>
          </div>
        </CardHeader>
        <CardContent className="p-0">
          <div className="overflow-x-auto">
            <Table>
              <TableHeader>
                <TableRow>
                  {isAdmin && (
                    <TableHead className="w-10 print:hidden">
                      <input
                        type="checkbox"
                        checked={semuaTerpilih}
                        onChange={toggleSemua}
                        aria-label="Pilih semua laporan"
                        className="h-4 w-4 rounded border-input"
                      />
                    </TableHead>
                  )}
                  <TableHead className="w-12">No</TableHead>
                  <TableHead className="w-24">Aksi</TableHead>
                  <TableHead className="min-w-[240px]">Judul</TableHead>
                  <TableHead>Semester</TableHead>
                  <TableHead>Tahun</TableHead>
                  <TableHead>Tanggal Upload</TableHead>
                  <TableHead>Tanggal Kirim</TableHead>
                  <TableHead>Berkas</TableHead>
                </TableRow>
              </TableHeader>
              <TableBody>
                {isLoading && (
                  <TableRow>
                    <TableCell
                      colSpan={kolom}
                      className="py-10 text-center text-sm text-muted-foreground"
                    >
                      Memuat laporan…
                    </TableCell>
                  </TableRow>
                )}
                {rows.map((row, index) => (
                  <TableRow key={row.id}>
                    {isAdmin && (
                      <TableCell className="print:hidden">
                        <input
                          type="checkbox"
                          checked={selected.includes(row.id)}
                          onChange={() => toggleSatu(row.id)}
                          aria-label={`Pilih ${row.judul}`}
                          className="h-4 w-4 rounded border-input"
                        />
                      </TableCell>
                    )}
                    <TableCell className="text-xs text-muted-foreground">
                      {index + 1}
                    </TableCell>
                    <TableCell className="print:hidden">
                      {isAdmin && (
                        <div className="flex gap-1">
                          <Button
                            variant="ghost"
                            size="icon"
                            className="h-8 w-8"
                            onClick={() => bukaEdit(row)}
                            aria-label={`Ubah laporan ${row.tahun} semester ${row.semester}`}
                          >
                            <Pencil className="h-4 w-4" />
                          </Button>
                          <Button
                            variant="ghost"
                            size="icon"
                            className="h-8 w-8 text-destructive hover:text-destructive"
                            onClick={() => setDeleteTarget(row)}
                            aria-label={`Hapus laporan ${row.tahun} semester ${row.semester}`}
                          >
                            <Trash2 className="h-4 w-4" />
                          </Button>
                        </div>
                      )}
                    </TableCell>
                    <TableCell>
                      <span className="text-sm font-medium">{row.judul}</span>
                      {(row.satuan || row.keterangan) && (
                        <span className="block text-xs text-muted-foreground">
                          {[row.satuan, row.keterangan]
                            .filter(Boolean)
                            .join(" · ")}
                        </span>
                      )}
                    </TableCell>
                    <TableCell>
                      <Badge variant="secondary">{row.semester}</Badge>
                    </TableCell>
                    <TableCell className="font-semibold">{row.tahun}</TableCell>
                    <TableCell className="text-xs">
                      {formatDate(row.createdAt)}
                    </TableCell>
                    <TableCell className="text-xs">
                      {row.tanggalKirim ? (
                        formatDate(row.tanggalKirim)
                      ) : (
                        <span className="text-muted-foreground">
                          Belum dikirim
                        </span>
                      )}
                    </TableCell>
                    <TableCell>
                      <a
                        href={`/api/backend/keuangan/apbdes/${row.id}/berkas`}
                        target="_blank"
                        rel="noreferrer"
                        className="inline-flex items-center gap-1 text-xs font-medium text-primary hover:underline"
                      >
                        <FolderOpen className="h-3.5 w-3.5" />
                        {ukuranFile(row.ukuran)}
                      </a>
                    </TableCell>
                  </TableRow>
                ))}
                {!isLoading && !rows.length && (
                  <TableRow>
                    <TableCell colSpan={kolom} className="py-14 text-center">
                      <p className="font-semibold">Belum ada laporan APBDes</p>
                      <p className="mt-1 text-sm text-muted-foreground">
                        Unggah laporan realisasi APBDes per semester dalam
                        format PDF.
                      </p>
                    </TableCell>
                  </TableRow>
                )}
              </TableBody>
            </Table>
          </div>
        </CardContent>
      </Card>

      <Dialog open={open} onOpenChange={(value) => !value && setOpen(false)}>
        <DialogContent className="max-w-lg">
          <DialogHeader>
            <DialogTitle>
              {editing ? "Ganti laporan APBDes" : "Tambah laporan APBDes"}
            </DialogTitle>
            <DialogDescription>
              Satu laporan untuk setiap tahun dan semester. Mengunggah ulang
              akan mengganti berkas sebelumnya.
            </DialogDescription>
          </DialogHeader>
          <form onSubmit={simpan} className="space-y-4">
            <div className="space-y-1.5">
              <Label className="text-xs">Judul</Label>
              <Input
                value={judul}
                onChange={(event) => setJudul(event.target.value)}
                required
                maxLength={200}
              />
            </div>
            <div className="grid gap-3 sm:grid-cols-2">
              <div className="space-y-1.5">
                <Label className="text-xs">Tahun</Label>
                <Select
                  value={tahun}
                  onChange={(event) => pilihTahun(event.target.value)}
                  disabled={!!editing}
                  aria-label="Pilih tahun laporan"
                >
                  {opsiTahun.map((nomor) => (
                    <option key={nomor} value={nomor}>
                      {nomor}
                    </option>
                  ))}
                </Select>
              </div>
              <div className="space-y-1.5">
                <Label className="text-xs">Semester</Label>
                <Select
                  value={semester}
                  onChange={(event) => pilihSemester(event.target.value)}
                  disabled={!!editing}
                  aria-label="Pilih semester"
                >
                  <option value="1">1</option>
                  <option value="2">2</option>
                </Select>
              </div>
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs">Satuan</Label>
              <Input
                value={satuan}
                onChange={(event) => setSatuan(event.target.value)}
                maxLength={100}
                placeholder="Pemdes Mulyadadi"
              />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs">Keterangan</Label>
              <Textarea
                value={keterangan}
                onChange={(event) => setKeterangan(event.target.value)}
                rows={2}
                maxLength={500}
                placeholder="Opsional"
              />
            </div>
            <div className="space-y-1.5">
              <Label className="text-xs">
                Berkas PDF{editing ? " (kosongkan jika tidak diganti)" : ""}
              </Label>
              <Input
                type="file"
                accept="application/pdf,.pdf"
                onChange={pilihBerkas}
                className="cursor-pointer"
              />
              {editing && !berkas && (
                <p className="text-xs text-muted-foreground">
                  Berkas saat ini: {editing.namaFile} ({ukuranFile(editing.ukuran)})
                </p>
              )}
              {berkas && (
                <p className="text-xs text-muted-foreground">
                  {berkas.nama} · {ukuranFile(berkas.ukuran)}
                </p>
              )}
            </div>
            <DialogFooter>
              <Button
                type="button"
                variant="outline"
                onClick={() => setOpen(false)}
              >
                Batal
              </Button>
              <Button type="submit" disabled={saving}>
                {saving ? "Menyimpan…" : "Simpan"}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>

      <Dialog
        open={!!deleteTarget}
        onOpenChange={(value) => !value && setDeleteTarget(null)}
      >
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Hapus laporan APBDes?</DialogTitle>
            <DialogDescription>
              {deleteTarget
                ? `${deleteTarget.judul} (${ukuranFile(deleteTarget.ukuran)}) akan dihapus permanen.`
                : ""}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setDeleteTarget(null)}>
              Batal
            </Button>
            <Button variant="destructive" onClick={hapus} disabled={deleting}>
              {deleting ? "Menghapus…" : "Hapus"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      <Dialog open={bulkOpen} onOpenChange={setBulkOpen}>
        <DialogContent className="max-w-md">
          <DialogHeader>
            <DialogTitle>Hapus {terpilih.length} laporan terpilih?</DialogTitle>
            <DialogDescription>
              Berkas PDF laporan yang dicentang akan dihapus permanen dari
              penyimpanan.
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="outline" onClick={() => setBulkOpen(false)}>
              Batal
            </Button>
            <Button
              variant="destructive"
              onClick={hapusTerpilih}
              disabled={deleting}
            >
              {deleting ? "Menghapus…" : "Hapus"}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
