"use client";

import { useEffect, useRef, useState } from "react";
import { Camera, Upload, X, Loader2, ImageOff } from "lucide-react";
import { getPB, fileUrl } from "@/lib/pocketbase";
import type { Pedido } from "@/lib/types/pedido";

/**
 * Captura/subida de fotos del croquis en papel. Reemplaza al editor de dibujo.
 *
 * - Modo SERVER (pedido existente): sube/borra directo en PocketBase y avisa con onServerChange.
 * - Modo LOCAL (pedido nuevo, sin id todavía): junta los File y los expone con onFilesChange;
 *   el padre los sube después de crear el pedido (uploadPedidoFotos).
 */
interface Props {
  pedido?: Pedido;                      // server mode
  files?: File[];                       // local mode
  onFilesChange?: (files: File[]) => void;
  onServerChange?: (pedido: Pedido) => void;
  readOnly?: boolean;
}

const MAX = 6;

// Formato unificado de salida: 4:3 a resolución fija + JPEG comprimido.
// Así toda foto (cámara nativa, galería, etc.) sale igual de tamaño y liviana,
// y se corrige la rotación EXIF que mete la cámara del celular.
const OUT_W = 1280;
const OUT_H = 960; // 4:3
const OUT_QUALITY = 0.82;

export function normalizeFotos(v: unknown): string[] {
  if (Array.isArray(v)) return v.filter(Boolean) as string[];
  if (typeof v === "string" && v) return [v];
  return [];
}

/**
 * Normaliza una imagen a 4:3 (recorte centrado tipo "cover"), resolución fija
 * OUT_W×OUT_H y JPEG comprimido. Respeta la orientación EXIF de la cámara.
 * Si algo falla, devuelve el File original para no bloquear la carga.
 */
export async function normalizeImage(file: File): Promise<File> {
  if (!file.type.startsWith("image/")) return file;
  try {
    const bmp = await createImageBitmap(file, { imageOrientation: "from-image" });
    const targetRatio = OUT_W / OUT_H;
    const srcRatio = bmp.width / bmp.height;
    let sw = bmp.width;
    let sh = bmp.height;
    let sx = 0;
    let sy = 0;
    if (srcRatio > targetRatio) {
      // más ancha que 4:3 → recorto los lados
      sw = Math.round(bmp.height * targetRatio);
      sx = Math.round((bmp.width - sw) / 2);
    } else {
      // más alta que 4:3 → recorto arriba/abajo
      sh = Math.round(bmp.width / targetRatio);
      sy = Math.round((bmp.height - sh) / 2);
    }
    const canvas = document.createElement("canvas");
    canvas.width = OUT_W;
    canvas.height = OUT_H;
    const ctx = canvas.getContext("2d");
    if (!ctx) {
      bmp.close();
      return file;
    }
    ctx.drawImage(bmp, sx, sy, sw, sh, 0, 0, OUT_W, OUT_H);
    bmp.close();
    const blob = await new Promise<Blob | null>((resolve) =>
      canvas.toBlob(resolve, "image/jpeg", OUT_QUALITY),
    );
    if (!blob) return file;
    const baseName = file.name.replace(/\.[^.]+$/, "") || "croquis";
    return new File([blob], `${baseName}.jpg`, { type: "image/jpeg", lastModified: Date.now() });
  } catch {
    return file;
  }
}

/** Sube fotos a un pedido recién creado (modo local del form nuevo). */
export async function uploadPedidoFotos(pedidoId: string, files: File[]): Promise<void> {
  if (!files.length) return;
  const fd = new FormData();
  for (const f of files) fd.append("dibujo_png+", f);
  await getPB().collection("pedidos").update(pedidoId, fd);
}

export default function PhotoCapture({ pedido, files, onFilesChange, onServerChange, readOnly }: Props) {
  const serverMode = !!pedido;
  const inputRef = useRef<HTMLInputElement>(null);
  const cameraRef = useRef<HTMLInputElement>(null);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [lightbox, setLightbox] = useState<string | null>(null);

  // previews locales (object URLs)
  const [localUrls, setLocalUrls] = useState<string[]>([]);
  useEffect(() => {
    if (serverMode || !files) return;
    const urls = files.map((f) => URL.createObjectURL(f));
    setLocalUrls(urls);
    return () => urls.forEach((u) => URL.revokeObjectURL(u));
  }, [files, serverMode]);

  const serverFotos = serverMode ? normalizeFotos(pedido!.dibujo_png) : [];
  const count = serverMode ? serverFotos.length : (files?.length || 0);

  async function handlePick(selected: FileList | null) {
    if (!selected || !selected.length) return;
    const raw = Array.from(selected).slice(0, MAX - count);
    setErr("");
    setBusy(true);
    try {
      // Normalizar todas a 4:3 / JPEG liviano antes de usarlas.
      const picked = await Promise.all(raw.map((f) => normalizeImage(f)));

      if (!serverMode) {
        onFilesChange?.([...(files || []), ...picked]);
        return;
      }
      // server mode → subir ya
      const fd = new FormData();
      for (const f of picked) fd.append("dibujo_png+", f);
      const updated = await getPB().collection("pedidos").update<Pedido>(pedido!.id, fd, { expand: "cliente" });
      onServerChange?.(updated);
    } catch (e) {
      setErr("No se pudo procesar la foto. " + (e as Error).message);
    } finally {
      setBusy(false);
      if (inputRef.current) inputRef.current.value = "";
      if (cameraRef.current) cameraRef.current.value = "";
    }
  }

  async function removeServer(filename: string) {
    if (!confirm("¿Borrar esta foto del croquis? Esta acción no se puede deshacer.")) return;
    setBusy(true);
    setErr("");
    try {
      const updated = await getPB().collection("pedidos").update<Pedido>(
        pedido!.id,
        { "dibujo_png-": [filename] },
        { expand: "cliente" },
      );
      onServerChange?.(updated);
    } catch (e) {
      setErr("No se pudo borrar la foto. " + (e as Error).message);
    } finally {
      setBusy(false);
    }
  }

  function removeLocal(idx: number) {
    if (!confirm("¿Quitar esta foto?")) return;
    onFilesChange?.((files || []).filter((_, i) => i !== idx));
  }

  const thumbs: { url: string; fullUrl: string; onRemove: () => void }[] = serverMode
    ? serverFotos.map((name) => ({
        url: fileUrl(pedido!, name, "400x0"),
        fullUrl: fileUrl(pedido!, name, "1280x0"),
        onRemove: () => removeServer(name),
      }))
    : (files || []).map((_, i) => ({ url: localUrls[i] || "", fullUrl: localUrls[i] || "", onRemove: () => removeLocal(i) }));

  return (
    <div>
      {/* Galería / archivos (varias) */}
      <input
        ref={inputRef}
        type="file"
        accept="image/*"
        multiple
        className="hidden"
        onChange={(e) => handlePick(e.target.files)}
      />
      {/* Cámara directa (celular) */}
      <input
        ref={cameraRef}
        type="file"
        accept="image/*"
        capture="environment"
        className="hidden"
        onChange={(e) => handlePick(e.target.files)}
      />

      {thumbs.length === 0 && !busy && (
        <div className="grid place-items-center rounded-xl border border-dashed border-line bg-canvas/40 px-4 py-8 text-center">
          <ImageOff className="mb-2 h-7 w-7 text-faint opacity-50" />
          <p className="text-sm text-faint">Sin fotos del croquis todavía.</p>
        </div>
      )}

      {(thumbs.length > 0 || busy) && (
        <div className="grid grid-cols-2 gap-2 sm:grid-cols-3">
          {thumbs.map((t, i) => (
            <div key={i} className="group relative aspect-[4/3] overflow-hidden rounded-xl border border-line bg-canvas">
              {/* eslint-disable-next-line @next/next/no-img-element */}
              <img
                src={t.url}
                alt={`Foto ${i + 1}`}
                className="h-full w-full object-cover cursor-zoom-in"
                onClick={() => setLightbox(t.fullUrl)}
              />
              {!readOnly && (
                <button
                  type="button"
                  onClick={t.onRemove}
                  disabled={busy}
                  aria-label="Quitar foto"
                  className="absolute right-1 top-1 grid h-6 w-6 place-items-center rounded-full bg-black/55 text-white opacity-0 transition-opacity hover:bg-bad group-hover:opacity-100"
                >
                  <X size={13} />
                </button>
              )}
            </div>
          ))}
          {busy && (
            <div className="grid aspect-[4/3] place-items-center rounded-xl border border-line bg-canvas">
              <Loader2 className="h-5 w-5 animate-spin text-faint" />
            </div>
          )}
        </div>
      )}

      {!readOnly && count < MAX && (
        <div className="mt-3 flex flex-wrap gap-2">
          <button
            type="button"
            onClick={() => cameraRef.current?.click()}
            disabled={busy}
            className="inline-flex items-center gap-2 rounded-xl bg-brand px-3.5 py-2 text-sm font-semibold text-white transition-colors hover:bg-brand-dark disabled:opacity-50"
          >
            <Camera size={16} /> Sacar foto
          </button>
          <button
            type="button"
            onClick={() => inputRef.current?.click()}
            disabled={busy}
            className="inline-flex items-center gap-2 rounded-xl border border-line bg-surface px-3.5 py-2 text-sm font-semibold text-ink transition-colors hover:border-brand disabled:opacity-50"
          >
            <Upload size={16} /> Subir
          </button>
        </div>
      )}

      {count >= MAX && <p className="mt-2 text-xs text-faint">Máximo {MAX} fotos.</p>}
      {err && <p className="mt-2 text-xs text-bad">{err}</p>}

      {lightbox && (
        <div
          className="fixed inset-0 z-50 flex items-center justify-center bg-black/85 p-4"
          onClick={() => setLightbox(null)}
        >
          {/* eslint-disable-next-line @next/next/no-img-element */}
          <img
            src={lightbox}
            alt="Foto ampliada"
            className="max-h-full max-w-full rounded-xl object-contain shadow-2xl"
            onClick={(e) => e.stopPropagation()}
          />
          <button
            type="button"
            onClick={() => setLightbox(null)}
            className="absolute right-4 top-4 grid h-9 w-9 place-items-center rounded-full bg-black/60 text-white hover:bg-black/80"
            aria-label="Cerrar"
          >
            <X size={18} />
          </button>
        </div>
      )}
    </div>
  );
}
