"use client";

import { useRef, useState } from "react";
import Image from "next/image";
import { ImagePlus, X, Loader2 } from "lucide-react";
import { LIMITS } from "@/lib/limits";

interface TripImageUploadProps {
  /** URL gambar yang sudah terunggah (path `/api/trip-images/...`). */
  value: string[];
  onChange: (urls: string[]) => void;
  /** Lapor error ke form (mis. file terlalu besar / gagal upload). */
  onError?: (msg: string) => void;
}

const ACCEPT_MIME = "image/jpeg,image/png,image/webp";
/** Sinkron dengan MAX_TRIP_IMAGE_UPLOAD_BYTES di lib/trip-image-storage.ts. */
const MAX_BYTES = 12 * 1024 * 1024;

/**
 * Pengganti input URL foto: user memilih file dari perangkatnya, tiap file
 * langsung di-upload & dikompres server-side. Form hanya menyimpan URL hasil.
 */
export function TripImageUpload({
  value,
  onChange,
  onError,
}: TripImageUploadProps) {
  const inputRef = useRef<HTMLInputElement>(null);
  const [uploadingCount, setUploadingCount] = useState(0);
  const max = LIMITS.MAX_IMAGE_URLS;
  const usedSlots = value.length + uploadingCount;
  const remaining = max - usedSlots;

  async function uploadOne(file: File): Promise<string | null> {
    if (!ACCEPT_MIME.split(",").includes(file.type)) {
      onError?.(`"${file.name}" harus JPG, PNG, atau WebP`);
      return null;
    }
    if (file.size > MAX_BYTES) {
      onError?.(`"${file.name}" melebihi 12MB`);
      return null;
    }
    const fd = new FormData();
    fd.set("file", file);
    try {
      const res = await fetch("/api/upload/trip-image", {
        method: "POST",
        body: fd,
      });
      const json = await res.json();
      if (!res.ok) {
        onError?.(json.error ?? `Gagal mengunggah "${file.name}"`);
        return null;
      }
      return json.url as string;
    } catch {
      onError?.(`Gagal mengunggah "${file.name}"`);
      return null;
    }
  }

  async function handlePick(e: React.ChangeEvent<HTMLInputElement>) {
    const files = Array.from(e.target.files ?? []);
    e.target.value = "";
    if (files.length === 0) return;

    if (remaining <= 0) {
      onError?.(`Maksimal ${max} foto`);
      return;
    }
    const picked = files.slice(0, remaining);
    if (files.length > remaining) {
      onError?.(`Hanya ${remaining} foto pertama diunggah (maks ${max})`);
    }

    setUploadingCount((c) => c + picked.length);
    // `value` di-snapshot saat handler dibuat; upload sekuensial supaya urutan
    // foto stabil, lalu hasil yang berhasil ditambahkan sekali di akhir.
    const uploaded: string[] = [];
    for (const file of picked) {
      const url = await uploadOne(file);
      setUploadingCount((c) => c - 1);
      if (url) uploaded.push(url);
    }
    if (uploaded.length > 0) onChange([...value, ...uploaded]);
  }

  function removeAt(index: number) {
    onChange(value.filter((_, i) => i !== index));
  }

  return (
    <div>
      <label className="mb-2 flex items-center justify-between">
        <span className="text-sm font-semibold text-neutral-700">
          Foto Trip
        </span>
        <span className="text-xs text-neutral-400">
          {value.length}/{max}
        </span>
      </label>

      <div className="grid grid-cols-3 gap-2 sm:grid-cols-4">
        {value.map((url, i) => (
          <div
            key={url}
            className="group relative aspect-square overflow-hidden rounded-xl border border-neutral-200 bg-neutral-100"
          >
            <Image
              src={url}
              alt={i === 0 ? "Foto cover" : `Foto ${i + 1}`}
              fill
              className="object-cover"
              sizes="(max-width: 640px) 33vw, 160px"
            />
            {i === 0 && (
              <span className="absolute left-1 top-1 rounded-md bg-primary-600/90 px-1.5 py-0.5 text-[10px] font-bold text-white">
                Cover
              </span>
            )}
            <button
              type="button"
              onClick={() => removeAt(i)}
              aria-label={`Hapus foto ${i + 1}`}
              className="absolute right-1 top-1 flex h-6 w-6 items-center justify-center rounded-full bg-black/55 text-white transition-colors hover:bg-red-600"
            >
              <X size={13} strokeWidth={2.5} aria-hidden />
            </button>
          </div>
        ))}

        {Array.from({ length: uploadingCount }).map((_, i) => (
          <div
            key={`uploading-${i}`}
            className="flex aspect-square items-center justify-center rounded-xl border border-dashed border-neutral-300 bg-neutral-50"
          >
            <Loader2
              size={20}
              strokeWidth={2}
              aria-hidden
              className="animate-spin text-neutral-400"
            />
          </div>
        ))}

        {remaining > 0 && (
          <button
            type="button"
            onClick={() => inputRef.current?.click()}
            className="flex aspect-square flex-col items-center justify-center gap-1 rounded-xl border border-dashed border-neutral-300 bg-neutral-50/60 text-neutral-500 transition-colors hover:border-primary-400 hover:text-primary-600"
          >
            <ImagePlus size={20} strokeWidth={1.75} aria-hidden />
            <span className="text-[11px] font-semibold">Tambah</span>
          </button>
        )}
      </div>

      <input
        ref={inputRef}
        type="file"
        accept={ACCEPT_MIME}
        multiple
        onChange={handlePick}
        className="sr-only"
      />

      <p className="mt-1.5 text-xs text-neutral-400">
        Unggah langsung dari galeri/kamera — JPG, PNG, atau WebP, maks 12MB per
        foto. Foto pertama jadi cover. Gambar besar otomatis dikompres tanpa
        mengorbankan kualitas.
      </p>
    </div>
  );
}
