"use client";

import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import useSWR from "swr";
import { ArrowLeft, Frame, Save, Trash2, X } from "lucide-react";
import type { Map as LeafletMap } from "leaflet";
import { CircleMarker, Polygon, Polyline } from "react-leaflet";
import { toast } from "sonner";
import { ApiError, apiSend, fetcher } from "@/lib/api";
import type { Desa } from "@/lib/types";
import { downloadGpx, parsePath, stringifyPath, type LatLng } from "@/lib/gpx";
import { useSession } from "@/lib/use-session";
import { BaseLayerChoice, FitOnLoad, GpxUpload, MapShell } from "@/components/map/map-shell";
import { PageHeader } from "@/components/page-header";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";

const DEFAULT_CENTER: LatLng = [-7.3841, 109.0363];

function warnaAman(nilai: string, cadangan: string) {
  return /^#[0-9a-fA-F]{6}$/.test(nilai) ? nilai : cadangan;
}

export default function PetaWilayahPage() {
  const { user } = useSession();
  const isAdmin = user?.role === "ADMIN";
  const { data: desa, mutate } = useSWR<Desa>("/desa", fetcher);
  const mapRef = useRef<LeafletMap | null>(null);
  const [titik, setTitik] = useState<LatLng[]>([]);
  const [warna, setWarna] = useState("#0f766e");
  const [pinggir, setPinggir] = useState("#134e4a");
  const [zoom, setZoom] = useState(15);
  const [layer, setLayer] = useState("osm");
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    if (!desa) return;
    setTitik(parsePath(desa.wilayahPath));
    setWarna(desa.wilayahWarna ?? "#0f766e");
    setPinggir(desa.wilayahBorder ?? "#134e4a");
    setZoom(desa.wilayahZoom ?? 15);
  }, [desa]);

  const pusat: LatLng = titik[0] ?? DEFAULT_CENTER;

  async function simpan() {
    setSaving(true);
    try {
      await apiSend("/desa", "PUT", {
        wilayahPath: titik.length ? stringifyPath(titik) : "",
        wilayahWarna: warnaAman(warna, "#0f766e"),
        wilayahBorder: warnaAman(pinggir, "#134e4a"),
        wilayahZoom: zoom,
      });
      toast.success(titik.length ? "Batas wilayah desa tersimpan" : "Batas wilayah dikosongkan");
      await mutate();
    } catch (error) {
      toast.error(error instanceof ApiError ? error.message : "Gagal menyimpan batas wilayah");
    } finally {
      setSaving(false);
    }
  }

  return (
    <div className="animate-fade-in space-y-6">
      <PageHeader
        title="Peta Wilayah Desa"
        description="Gambar poligon batas wilayah. Hasilnya tampil sebagai area pada peta halaman depan website."
        action={
          <Button asChild variant="outline">
            <Link href="/admin/pengaturan">
              <ArrowLeft className="h-4 w-4" />
              Kembali ke Identitas Desa
            </Link>
          </Button>
        }
      />

      <div className="grid gap-5 lg:grid-cols-[1.6fr_1fr]">
        <Card>
          <CardHeader className="flex-row items-center justify-between space-y-0">
            <CardTitle className="text-base">{titik.length} titik sudut</CardTitle>
            <span className="text-xs text-muted-foreground">
              Klik peta untuk menambah titik, klik titik untuk menghapusnya
            </span>
          </CardHeader>
          <CardContent className="space-y-4">
            <MapShell
              center={pusat}
              zoom={zoom}
              layerId={layer}
              mapRef={(map) => {
                mapRef.current = map;
              }}
              onPoint={(p) => setTitik((current) => [...current, p])}
              onZoom={setZoom}
            >
              {titik.length > 1 && <FitOnLoad points={titik} token={desa?.wilayahPath ?? ""} />}
              {titik.length >= 3 && (
                <Polygon
                  positions={titik}
                  pathOptions={{
                    color: warnaAman(pinggir, "#134e4a"),
                    fillColor: warnaAman(warna, "#0f766e"),
                    fillOpacity: 0.35,
                    weight: 2,
                  }}
                />
              )}
              {titik.length === 2 && (
                <Polyline positions={titik} pathOptions={{ color: warnaAman(pinggir, "#134e4a") }} />
              )}
              {titik.map((point, index) => (
                <CircleMarker
                  key={`${point[0]}-${point[1]}-${index}`}
                  center={point}
                  radius={5}
                  pathOptions={{
                    color: "#ffffff",
                    fillColor: "#0f766e",
                    fillOpacity: 1,
                    bubblingMouseEvents: false,
                  }}
                  eventHandlers={{ click: () => setTitik((c) => c.filter((_, i) => i !== index)) }}
                />
              ))}
            </MapShell>

            {!titik.length && (
              <p className="text-sm text-muted-foreground">
                Belum ada poligon. Minimal tiga titik supaya area wilayah terbentuk.
              </p>
            )}

            <BaseLayerChoice value={layer} onChange={setLayer} />
          </CardContent>
        </Card>

        <Card>
          <CardHeader>
            <CardTitle className="text-base">Warna &amp; tampilan</CardTitle>
          </CardHeader>
          <CardContent className="space-y-4">
            <label className="block text-sm font-medium">
              Warna Area
              <div className="mt-1.5 flex gap-2">
                <input
                  type="color"
                  value={warnaAman(warna, "#0f766e")}
                  onChange={(event) => setWarna(event.target.value)}
                  className="h-9 w-12 cursor-pointer rounded-md border border-input bg-background p-1"
                />
                <Input value={warna} onChange={(event) => setWarna(event.target.value)} />
              </div>
            </label>

            <label className="block text-sm font-medium">
              Warna Pinggiran
              <div className="mt-1.5 flex gap-2">
                <input
                  type="color"
                  value={warnaAman(pinggir, "#134e4a")}
                  onChange={(event) => setPinggir(event.target.value)}
                  className="h-9 w-12 cursor-pointer rounded-md border border-input bg-background p-1"
                />
                <Input value={pinggir} onChange={(event) => setPinggir(event.target.value)} />
              </div>
            </label>

            <label className="block text-sm font-medium">
              Zoom
              <Input
                type="number"
                min={1}
                max={19}
                value={zoom}
                onChange={(event) => setZoom(Number(event.target.value) || 1)}
                className="mt-1.5"
              />
            </label>

            <div className="flex flex-wrap gap-2">
              <Button
                type="button"
                variant="outline"
                onClick={() => mapRef.current?.fitBounds(titik)}
                disabled={titik.length < 2}
              >
                <Frame className="h-4 w-4" />
                Sesuaikan tampilan
              </Button>
              <GpxUpload onPoints={setTitik} />
              <Button
                type="button"
                variant="outline"
                disabled={!titik.length}
                onClick={() => downloadGpx("batas-wilayah-desa.gpx", titik, "Batas Wilayah")}
              >
                Ekspor ke GPX
              </Button>
              <Button
                type="button"
                variant="outline"
                onClick={() => setTitik((current) => current.slice(0, -1))}
                disabled={!titik.length}
              >
                <X className="h-4 w-4" />
                Hapus titik terakhir
              </Button>
            </div>

            {isAdmin && (
              <div className="flex flex-wrap gap-2 border-t pt-4">
                <Button onClick={simpan} disabled={saving}>
                  <Save className="h-4 w-4" />
                  {saving ? "Menyimpan…" : "Simpan"}
                </Button>
                <Button
                  variant="ghost"
                  disabled={saving}
                  onClick={() => setTitik([])}
                  className="text-muted-foreground"
                >
                  <Trash2 className="h-4 w-4" />
                  Kosongkan
                </Button>
              </div>
            )}
          </CardContent>
        </Card>
      </div>
    </div>
  );
}
