"use client";

import { useMemo, useRef, useState } from "react";
import { getSupabaseClient } from "@/lib/supabase";
import { encolherParaUpload } from "@/lib/fotos/encolher";
import { Upload, X, Loader2, Image as ImageIcon } from "lucide-react";
import Image from "next/image";

interface ImageUploadProps {
  bucket: string;
  folder?: string;
  value?: string;
  onChange: (url: string) => void;
  disabled?: boolean;
  className?: string;
  enableCrop?: boolean;
  cropAspect?: number;
  output?: {
    format?: "original" | "svg-webp";
    scale?: number;
    width?: number;
    height?: number;
    quality?: number;
  };
  /* O campo no formato da imagem pedida (banner largo, quadrado, retrato),
     com a foto à mostra e os botões ao lado. Sem isto, o quadrado de sempre.
     Erro de envio aparece no próprio campo, nunca em alerta do navegador. */
  visual?: { proporcao: number; dica?: string };
}

type CropEditorState = {
  file: File;
  dataUrl: string;
  naturalWidth: number;
  naturalHeight: number;
  viewportWidth: number;
  viewportHeight: number;
  zoom: number;
  minZoom: number;
  x: number;
  y: number;
  crop: {
    x: number;
    y: number;
    width: number;
    height: number;
  };
};

type CropHandle = "nw" | "ne" | "sw" | "se";

function clamp(value: number, min: number, max: number) {
  return Math.min(Math.max(value, min), max);
}

function getCropViewport(aspect: number) {
  const safeAspect = Number.isFinite(aspect) && aspect > 0 ? aspect : 1;
  if (safeAspect >= 1) {
    return { width: 320, height: Math.round(320 / safeAspect) };
  }

  return { width: Math.round(320 * safeAspect), height: 320 };
}

function getPanLimits(state: CropEditorState, zoom = state.zoom) {
  const displayWidth = state.naturalWidth * zoom;
  const displayHeight = state.naturalHeight * zoom;
  return {
    maxX: Math.max(0, (displayWidth - state.viewportWidth) / 2),
    maxY: Math.max(0, (displayHeight - state.viewportHeight) / 2),
  };
}

function clampPan(state: CropEditorState, x: number, y: number, zoom = state.zoom) {
  const { maxX, maxY } = getPanLimits(state, zoom);
  return {
    x: clamp(x, -maxX, maxX),
    y: clamp(y, -maxY, maxY),
  };
}

function getInitialCropRect(viewportWidth: number, viewportHeight: number, aspect: number) {
  const safeAspect = Number.isFinite(aspect) && aspect > 0 ? aspect : 1;
  const horizontalPadding = Math.max(16, Math.round(viewportWidth * 0.08));
  const verticalPadding = Math.max(16, Math.round(viewportHeight * 0.08));
  const maxWidth = viewportWidth - horizontalPadding * 2;
  const maxHeight = viewportHeight - verticalPadding * 2;

  let width = maxWidth;
  let height = width / safeAspect;

  if (height > maxHeight) {
    height = maxHeight;
    width = height * safeAspect;
  }

  return {
    x: Math.round((viewportWidth - width) / 2),
    y: Math.round((viewportHeight - height) / 2),
    width: Math.round(width),
    height: Math.round(height),
  };
}

export default function ImageUpload({
  bucket,
  folder = "",
  value,
  onChange,
  disabled,
  className = "",
  enableCrop = false,
  cropAspect = 1,
  output,
  visual,
}: ImageUploadProps) {
  const [uploading, setUploading] = useState(false);
  const [erroDoEnvio, setErroDoEnvio] = useState("");
  const [cropEditor, setCropEditor] = useState<CropEditorState | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const dragStateRef = useRef<{
    pointerId: number;
    startX: number;
    startY: number;
    originX: number;
    originY: number;
  } | null>(null);
  const cropDragStateRef = useRef<{
    pointerId: number;
    mode: "move" | "resize";
    handle?: CropHandle;
    startX: number;
    startY: number;
    originCrop: {
      x: number;
      y: number;
      width: number;
      height: number;
    };
  } | null>(null);
  const cropViewportRef = useRef<HTMLDivElement>(null);
  const passthroughLoader = ({ src }: { src: string }) => src;

  const panLimits = useMemo(() => {
    if (!cropEditor) return { maxX: 0, maxY: 0 };
    return getPanLimits(cropEditor);
  }, [cropEditor]);

  const fileToDataUrl = async (blob: Blob) => {
    return await new Promise<string>((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(String(reader.result || ""));
      reader.onerror = () => reject(reader.error);
      reader.readAsDataURL(blob);
    });
  };

  const stripJpegXmp = async (file: File) => {
    const buffer = await file.arrayBuffer();
    const bytes = new Uint8Array(buffer);
    if (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8) return file;

    const out: number[] = [];
    out.push(0xff, 0xd8);

    let i = 2;
    while (i + 3 < bytes.length) {
      if (bytes[i] !== 0xff) break;
      const marker = bytes[i + 1];

      if (marker === 0xda) {
        for (let j = i; j < bytes.length; j++) out.push(bytes[j]);
        break;
      }

      if (marker === 0xd9) {
        out.push(0xff, 0xd9);
        break;
      }

      const hasLength = marker >= 0xc0 && marker !== 0xd8 && marker !== 0xd9 && marker !== 0x01 && !(marker >= 0xd0 && marker <= 0xd7);
      if (!hasLength) {
        out.push(0xff, marker);
        i += 2;
        continue;
      }

      const len = (bytes[i + 2] << 8) | bytes[i + 3];
      if (len < 2 || i + 2 + len > bytes.length) break;

      const segStart = i;
      const segEnd = i + 2 + len;

      let keep = true;
      if (marker === 0xe1) {
        const payload = bytes.slice(i + 4, segEnd);
        const xmpHeader = "http://ns.adobe.com/xap/1.0/\0";
        if (payload.length >= xmpHeader.length) {
          let isXmp = true;
          for (let k = 0; k < xmpHeader.length; k++) {
            if (payload[k] !== xmpHeader.charCodeAt(k)) {
              isXmp = false;
              break;
            }
          }
          if (isXmp) keep = false;
        }
      }

      if (keep) {
        for (let j = segStart; j < segEnd; j++) out.push(bytes[j]);
      }

      i = segEnd;
    }

    const stripped = new Uint8Array(out);
    if (stripped.byteLength >= bytes.byteLength) return file;

    return new File([stripped], file.name, { type: file.type });
  };

  const convertToSvgWebp = async (file: File) => {
    const scale = output?.scale ?? 0.7;
    const targetWidth = output?.width ?? 1920;
    const targetHeight = output?.height ?? 640;
    const quality = output?.quality ?? 0.82;

    const width = Math.max(1, Math.round(targetWidth * scale));
    const height = Math.max(1, Math.round(targetHeight * scale));

    const bitmap = await createImageBitmap(file);
    const canvas = document.createElement("canvas");
    canvas.width = width;
    canvas.height = height;

    const ctx = canvas.getContext("2d");
    if (!ctx) throw new Error("Canvas context unavailable");

    const srcAspect = bitmap.width / bitmap.height;
    const dstAspect = width / height;

    let sx = 0;
    let sy = 0;
    let sw = bitmap.width;
    let sh = bitmap.height;

    if (srcAspect > dstAspect) {
      sh = bitmap.height;
      sw = Math.round(sh * dstAspect);
      sx = Math.round((bitmap.width - sw) / 2);
      sy = 0;
    } else {
      sw = bitmap.width;
      sh = Math.round(sw / dstAspect);
      sx = 0;
      sy = Math.round((bitmap.height - sh) / 2);
    }

    ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, width, height);

    const webpBlob = await new Promise<Blob>((resolve, reject) => {
      canvas.toBlob(
        (blob) => {
          if (!blob) reject(new Error("Failed to encode WebP"));
          else resolve(blob);
        },
        "image/webp",
        quality
      );
    });

    const dataUrl = await fileToDataUrl(webpBlob);
    const svg = [
      `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}">`,
      `<image href="${dataUrl}" width="${width}" height="${height}" preserveAspectRatio="xMidYMid slice" />`,
      "</svg>",
    ].join("");

    return new File([svg], `${file.name.replace(/\.[^/.]+$/, "")}.svg`, {
      type: "image/svg+xml",
    });
  };

  const uploadPreparedFile = async (selectedFile: File) => {
    /* Fora do banner em SVG, a foto sobe encolhida (1600 px, WebP): o
       original de celular não precisa ir inteiro para o Storage. */
    const file =
      output?.format === "svg-webp"
        ? await convertToSvgWebp(selectedFile)
        : await encolherParaUpload(await stripJpegXmp(selectedFile));

    const supabase = getSupabaseClient();
    const fileExt = file.name.split(".").pop();
    const fileName = `${folder ? `${folder}/` : ""}${Math.random().toString(36).substring(2, 15)}_${Date.now()}.${fileExt}`;

    const { error: uploadError } = await supabase.storage
      .from(bucket)
      .upload(fileName, file);

    if (uploadError) {
      throw uploadError;
    }

    const { data } = supabase.storage.from(bucket).getPublicUrl(fileName);
    onChange(data.publicUrl);
  };

  const openCropEditor = async (selectedFile: File) => {
    const [dataUrl, bitmap] = await Promise.all([
      fileToDataUrl(selectedFile),
      createImageBitmap(selectedFile),
    ]);

    const naturalWidth = bitmap.width;
    const naturalHeight = bitmap.height;
    bitmap.close();

    const { width: viewportWidth, height: viewportHeight } = getCropViewport(cropAspect);
    const minZoom = Math.max(
      viewportWidth / naturalWidth,
      viewportHeight / naturalHeight
    );
    const initialCrop = getInitialCropRect(viewportWidth, viewportHeight, cropAspect);

    setCropEditor({
      file: selectedFile,
      dataUrl,
      naturalWidth,
      naturalHeight,
      viewportWidth,
      viewportHeight,
      zoom: minZoom,
      minZoom,
      x: 0,
      y: 0,
      crop: initialCrop,
    });
  };

  const createCroppedImageFile = async (state: CropEditorState) => {
    const image = await new Promise<HTMLImageElement>((resolve, reject) => {
      const img = new window.Image();
      img.onload = () => resolve(img);
      img.onerror = () => reject(new Error("Nao foi possivel carregar a imagem para recorte."));
      img.src = state.dataUrl;
    });

    const scale = state.zoom;
    const displayWidth = state.naturalWidth * scale;
    const displayHeight = state.naturalHeight * scale;
    const imageLeft = state.viewportWidth / 2 + state.x - displayWidth / 2;
    const imageTop = state.viewportHeight / 2 + state.y - displayHeight / 2;

    const sourceWidth = state.crop.width / scale;
    const sourceHeight = state.crop.height / scale;
    const maxSourceX = Math.max(0, state.naturalWidth - sourceWidth);
    const maxSourceY = Math.max(0, state.naturalHeight - sourceHeight);
    const sourceX = clamp((state.crop.x - imageLeft) / scale, 0, maxSourceX);
    const sourceY = clamp((state.crop.y - imageTop) / scale, 0, maxSourceY);

    const canvas = document.createElement("canvas");
    canvas.width = Math.max(1, Math.round(sourceWidth));
    canvas.height = Math.max(1, Math.round(sourceHeight));

    const ctx = canvas.getContext("2d");
    if (!ctx) throw new Error("Canvas context unavailable");

    ctx.drawImage(
      image,
      sourceX,
      sourceY,
      sourceWidth,
      sourceHeight,
      0,
      0,
      canvas.width,
      canvas.height
    );

    const mimeType = state.file.type === "image/jpeg" ? "image/jpeg" : "image/png";
    const blob = await new Promise<Blob>((resolve, reject) => {
      canvas.toBlob(
        (croppedBlob) => {
          if (!croppedBlob) {
            reject(new Error("Nao foi possivel gerar a imagem recortada."));
            return;
          }
          resolve(croppedBlob);
        },
        mimeType,
        mimeType === "image/jpeg" ? 0.92 : undefined
      );
    });

    const baseName = state.file.name.replace(/\.[^/.]+$/, "");
    const extension = mimeType === "image/jpeg" ? "jpg" : "png";
    return new File([blob], `${baseName}-crop.${extension}`, { type: mimeType });
  };

  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFile = e.target.files?.[0];
    if (!selectedFile) return;
    setErroDoEnvio("");

    if (fileInputRef.current) {
      fileInputRef.current.value = "";
    }

    try {
      if (enableCrop && selectedFile.type.startsWith("image/")) {
        await openCropEditor(selectedFile);
        return;
      }

      setUploading(true);
      await uploadPreparedFile(selectedFile);
    } catch (error) {
      console.error("Error uploading image:", error);
      if (visual) setErroDoEnvio("Não deu para enviar a imagem. Tente de novo.");
      else alert("Erro ao fazer upload da imagem");
    } finally {
      setUploading(false);
    }
  };

  const handleApplyCrop = async () => {
    if (!cropEditor) return;

    try {
      setUploading(true);
      const croppedFile = await createCroppedImageFile(cropEditor);
      await uploadPreparedFile(croppedFile);
      setCropEditor(null);
      dragStateRef.current = null;
    } catch (error) {
      console.error("Error cropping/uploading image:", error);
      if (visual) setErroDoEnvio("Não deu para recortar e enviar a imagem. Tente de novo.");
      else alert("Erro ao editar a imagem");
    } finally {
      setUploading(false);
    }
  };

  const closeCropEditor = () => {
    dragStateRef.current = null;
    cropDragStateRef.current = null;
    setCropEditor(null);
  };

  const handleCropPointerDown = (event: React.PointerEvent<HTMLDivElement>) => {
    if (!cropEditor || uploading) return;
    event.currentTarget.setPointerCapture(event.pointerId);
    dragStateRef.current = {
      pointerId: event.pointerId,
      startX: event.clientX,
      startY: event.clientY,
      originX: cropEditor.x,
      originY: cropEditor.y,
    };
  };

  const handleCropPointerMove = (event: React.PointerEvent<HTMLDivElement>) => {
    const cropDragState = cropDragStateRef.current;
    if (cropEditor && cropDragState && cropDragState.pointerId === event.pointerId) {
      const minWidth = 56;
      const minHeight = 56;
      const deltaX = event.clientX - cropDragState.startX;
      const deltaY = event.clientY - cropDragState.startY;

      setCropEditor((current) => {
        if (!current) return current;
        const origin = cropDragState.originCrop;

        if (cropDragState.mode === "move") {
          const nextX = clamp(origin.x + deltaX, 0, current.viewportWidth - origin.width);
          const nextY = clamp(origin.y + deltaY, 0, current.viewportHeight - origin.height);
          return {
            ...current,
            crop: {
              ...current.crop,
              x: Math.round(nextX),
              y: Math.round(nextY),
            },
          };
        }

        if (!cropDragState.handle) return current;

        const right = origin.x + origin.width;
        const bottom = origin.y + origin.height;

        if (cropDragState.handle === "se") {
          const maxWidth = current.viewportWidth - origin.x;
          const maxHeight = current.viewportHeight - origin.y;
          const width = clamp(origin.width + deltaX, minWidth, maxWidth);
          const height = clamp(origin.height + deltaY, minHeight, maxHeight);
          return { ...current, crop: { x: origin.x, y: origin.y, width: Math.round(width), height: Math.round(height) } };
        }

        if (cropDragState.handle === "ne") {
          const maxWidth = current.viewportWidth - origin.x;
          const maxHeight = bottom;
          const width = clamp(origin.width + deltaX, minWidth, maxWidth);
          const height = clamp(origin.height - deltaY, minHeight, maxHeight);
          return {
            ...current,
            crop: {
              x: origin.x,
              y: Math.round(bottom - height),
              width: Math.round(width),
              height: Math.round(height),
            },
          };
        }

        if (cropDragState.handle === "sw") {
          const maxWidth = right;
          const maxHeight = current.viewportHeight - origin.y;
          const width = clamp(origin.width - deltaX, minWidth, maxWidth);
          const height = clamp(origin.height + deltaY, minHeight, maxHeight);
          return {
            ...current,
            crop: {
              x: Math.round(right - width),
              y: origin.y,
              width: Math.round(width),
              height: Math.round(height),
            },
          };
        }

        const maxWidth = right;
        const maxHeight = bottom;
        const width = clamp(origin.width - deltaX, minWidth, maxWidth);
        const height = clamp(origin.height - deltaY, minHeight, maxHeight);
        return {
          ...current,
          crop: {
            x: Math.round(right - width),
            y: Math.round(bottom - height),
            width: Math.round(width),
            height: Math.round(height),
          },
        };
      });

      return;
    }

    const dragState = dragStateRef.current;
    if (!cropEditor || !dragState || dragState.pointerId !== event.pointerId) return;

    const deltaX = event.clientX - dragState.startX;
    const deltaY = event.clientY - dragState.startY;
    setCropEditor((current) => {
      if (!current) return current;
      const clamped = clampPan(
        current,
        dragState.originX + deltaX,
        dragState.originY + deltaY
      );
      return {
        ...current,
        ...clamped,
      };
    });
  };

  const handleCropPointerUp = (event: React.PointerEvent<HTMLDivElement>) => {
    if (dragStateRef.current?.pointerId === event.pointerId) {
      dragStateRef.current = null;
    }
    if (cropDragStateRef.current?.pointerId === event.pointerId) {
      cropDragStateRef.current = null;
    }
    if (cropViewportRef.current?.hasPointerCapture(event.pointerId)) {
      cropViewportRef.current.releasePointerCapture(event.pointerId);
    }
  };

  const handleCropRectPointerDown = (event: React.PointerEvent<HTMLDivElement>) => {
    if (!cropEditor || uploading) return;
    event.preventDefault();
    event.stopPropagation();
    cropViewportRef.current?.setPointerCapture(event.pointerId);
    cropDragStateRef.current = {
      pointerId: event.pointerId,
      mode: "move",
      startX: event.clientX,
      startY: event.clientY,
      originCrop: { ...cropEditor.crop },
    };
  };

  const handleCropResizePointerDown = (handle: CropHandle) => (event: React.PointerEvent<HTMLButtonElement>) => {
    if (!cropEditor || uploading) return;
    event.preventDefault();
    event.stopPropagation();
    cropViewportRef.current?.setPointerCapture(event.pointerId);
    cropDragStateRef.current = {
      pointerId: event.pointerId,
      mode: "resize",
      handle,
      startX: event.clientX,
      startY: event.clientY,
      originCrop: { ...cropEditor.crop },
    };
  };

  const handleRemove = () => {
    onChange("");
  };

  const campoDoArquivo = (
    <input
      type="file"
      accept="image/*"
      onChange={handleUpload}
      ref={fileInputRef}
      className="hidden"
      disabled={disabled || uploading}
    />
  );

  return (
    <div className={`flex flex-col gap-4 ${className}`}>
      {visual ? (
        <div className="flex flex-col gap-2">
          {campoDoArquivo}
          <button
            type="button"
            onClick={() => fileInputRef.current?.click()}
            disabled={disabled || uploading || Boolean(cropEditor)}
            className="group relative w-full overflow-hidden rounded-xl border border-[var(--ks-color-border-subtle)] bg-[var(--ks-color-bg-inset)] transition hover:border-[var(--ks-color-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--ks-color-primary)] disabled:opacity-60"
            style={{ aspectRatio: String(Math.max(0.5, Math.min(8, visual.proporcao))) }}
            aria-label={value ? "Trocar a imagem" : "Escolher a imagem"}
          >
            {value ? (
              /* eslint-disable-next-line @next/next/no-img-element */
              <img src={value} alt="" className="absolute inset-0 h-full w-full object-cover" />
            ) : (
              <span className="absolute inset-0 flex flex-col items-center justify-center gap-1.5 text-[var(--ks-color-primary)]">
                <Upload size={18} />
                <span className="text-xs font-bold">Escolher imagem</span>
              </span>
            )}
            {uploading ? (
              <span className="absolute inset-0 flex items-center justify-center bg-white/70">
                <Loader2 size={20} className="animate-spin text-[var(--ks-color-primary)]" />
              </span>
            ) : value ? (
              <span className="absolute inset-x-0 bottom-0 flex justify-end bg-gradient-to-t from-black/50 to-transparent p-2 opacity-0 transition group-hover:opacity-100">
                <span className="rounded-full bg-white px-3 py-1 text-[11px] font-bold text-[var(--ks-n-900)]">Trocar</span>
              </span>
            ) : null}
          </button>
          <div className="flex items-center justify-between gap-3">
            <p className="text-[11px] leading-4 text-[var(--ks-color-text-soft)]">{visual.dica || "JPG, PNG ou WebP. Você recorta depois de escolher."}</p>
            {value ? (
              <button
                type="button"
                onClick={handleRemove}
                disabled={disabled || uploading}
                className="shrink-0 text-[11px] font-bold text-[var(--ks-color-status-danger)] hover:underline disabled:opacity-50"
              >
                Tirar imagem
              </button>
            ) : null}
          </div>
          {erroDoEnvio ? <p className="text-[12px] font-semibold text-[var(--ks-color-status-danger)]">{erroDoEnvio}</p> : null}
        </div>
      ) : (
      <div className="flex items-center gap-4">
        {value ? (
          <div className="relative w-32 h-32 rounded-lg overflow-hidden border border-gray-200 group">
            <Image
              src={value}
              alt="Upload"
              width={128}
              height={128}
              sizes="128px"
              className="w-full h-full object-cover"
              loader={passthroughLoader}
              unoptimized
            />
            <button
              onClick={handleRemove}
              disabled={disabled || uploading}
              type="button"
              className="absolute top-1 right-1 p-1 bg-red-500 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity disabled:opacity-50"
            >
              <X size={14} />
            </button>
          </div>
        ) : (
          <div className="w-32 h-32 rounded-lg border-2 border-dashed border-gray-300 flex flex-col items-center justify-center text-gray-500 bg-gray-50">
            <ImageIcon size={24} className="mb-2" />
            <span className="text-xs text-center px-2">Nenhuma imagem</span>
          </div>
        )}

        <div className="flex flex-col gap-2">
          {campoDoArquivo}
          <button
            type="button"
            onClick={() => fileInputRef.current?.click()}
            disabled={disabled || uploading || Boolean(cropEditor)}
            className="flex items-center gap-2 px-4 py-2 bg-white border border-gray-300 rounded-md text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-[var(--ks-color-primary)] disabled:opacity-50"
          >
            {uploading ? (
              <Loader2 size={16} className="animate-spin" />
            ) : (
              <Upload size={16} />
            )}
            {uploading ? "Enviando..." : "Carregar Imagem"}
          </button>
          <p className="text-xs text-gray-500">JPG, PNG ou GIF ate 2MB</p>
          {enableCrop ? (
            <p className="text-xs text-gray-500">
              Depois de selecionar, voce pode recortar e ajustar a imagem.
            </p>
          ) : null}
        </div>
      </div>
      )}

      {cropEditor ? (
        <div className="fixed inset-0 z-[120] bg-black/55 backdrop-blur-[1px] flex items-center justify-center p-4">
          <div className="w-full max-w-2xl rounded-2xl bg-white border border-gray-200 shadow-2xl p-5 space-y-4">
            <div className="space-y-1">
              <h3 className="text-lg font-semibold text-gray-900">Editar imagem</h3>
              <p className="text-sm text-gray-500">
                Arraste a imagem e ajuste a área de corte pelas alças.
              </p>
            </div>

            <div className="rounded-xl border border-gray-200 bg-gray-50 p-4">
              <div
                ref={cropViewportRef}
                className="relative mx-auto overflow-hidden rounded-xl ring-1 ring-[rgba(255,255,255,0.75)] touch-none bg-white cursor-grab active:cursor-grabbing"
                style={{
                  width: `${cropEditor.viewportWidth}px`,
                  height: `${cropEditor.viewportHeight}px`,
                }}
                onPointerDown={handleCropPointerDown}
                onPointerMove={handleCropPointerMove}
                onPointerUp={handleCropPointerUp}
                onPointerCancel={handleCropPointerUp}
              >
                <Image
                  src={cropEditor.dataUrl}
                  alt="Preview de recorte"
                  width={cropEditor.naturalWidth}
                  height={cropEditor.naturalHeight}
                  loader={passthroughLoader}
                  unoptimized
                  className="absolute left-1/2 top-1/2 select-none max-w-none"
                  style={{
                    width: `${cropEditor.naturalWidth}px`,
                    height: `${cropEditor.naturalHeight}px`,
                    transform: `translate(calc(-50% + ${cropEditor.x}px), calc(-50% + ${cropEditor.y}px)) scale(${cropEditor.zoom})`,
                    transformOrigin: "center center",
                  }}
                />

                <div className="absolute inset-0 pointer-events-none">
                  <div
                    className="absolute border-2 border-white shadow-[0_0_0_9999px_rgba(15,23,42,0.42)] rounded-md"
                    style={{
                      left: `${cropEditor.crop.x}px`,
                      top: `${cropEditor.crop.y}px`,
                      width: `${cropEditor.crop.width}px`,
                      height: `${cropEditor.crop.height}px`,
                    }}
                  />
                </div>

                <div
                  className="absolute rounded-md ring-1 ring-white/90 bg-transparent cursor-move"
                  style={{
                    left: `${cropEditor.crop.x}px`,
                    top: `${cropEditor.crop.y}px`,
                    width: `${cropEditor.crop.width}px`,
                    height: `${cropEditor.crop.height}px`,
                  }}
                  onPointerDown={handleCropRectPointerDown}
                >
                  <button
                    type="button"
                    className="absolute -left-2 -top-2 h-4 w-4 rounded-full border border-white bg-[var(--ks-color-primary)] cursor-nwse-resize"
                    onPointerDown={handleCropResizePointerDown("nw")}
                  />
                  <button
                    type="button"
                    className="absolute -right-2 -top-2 h-4 w-4 rounded-full border border-white bg-[var(--ks-color-primary)] cursor-nesw-resize"
                    onPointerDown={handleCropResizePointerDown("ne")}
                  />
                  <button
                    type="button"
                    className="absolute -left-2 -bottom-2 h-4 w-4 rounded-full border border-white bg-[var(--ks-color-primary)] cursor-nesw-resize"
                    onPointerDown={handleCropResizePointerDown("sw")}
                  />
                  <button
                    type="button"
                    className="absolute -right-2 -bottom-2 h-4 w-4 rounded-full border border-white bg-[var(--ks-color-primary)] cursor-nwse-resize"
                    onPointerDown={handleCropResizePointerDown("se")}
                  />
                </div>
              </div>
            </div>

            <div className="space-y-3">
              <label className="block text-sm text-gray-700">
                <span className="block mb-1">Zoom</span>
                <input
                  type="range"
                  min={cropEditor.minZoom}
                  max={Math.max(cropEditor.minZoom * 4, cropEditor.minZoom + 0.01)}
                  step={0.01}
                  value={cropEditor.zoom}
                  onChange={(event) => {
                    const nextZoom = Number(event.target.value);
                    setCropEditor((current) => {
                      if (!current) return current;
                      const clamped = clampPan(current, current.x, current.y, nextZoom);
                      return {
                        ...current,
                        zoom: nextZoom,
                        ...clamped,
                      };
                    });
                  }}
                />
              </label>

              <label className="block text-sm text-gray-700">
                <span className="block mb-1">Posicao horizontal</span>
                <input
                  type="range"
                  min={-panLimits.maxX}
                  max={panLimits.maxX}
                  step={1}
                  value={cropEditor.x}
                  onChange={(event) => {
                    const nextX = Number(event.target.value);
                    setCropEditor((current) => {
                      if (!current) return current;
                      const clamped = clampPan(current, nextX, current.y);
                      return {
                        ...current,
                        ...clamped,
                      };
                    });
                  }}
                  disabled={panLimits.maxX <= 0}
                />
              </label>

              <label className="block text-sm text-gray-700">
                <span className="block mb-1">Posicao vertical</span>
                <input
                  type="range"
                  min={-panLimits.maxY}
                  max={panLimits.maxY}
                  step={1}
                  value={cropEditor.y}
                  onChange={(event) => {
                    const nextY = Number(event.target.value);
                    setCropEditor((current) => {
                      if (!current) return current;
                      const clamped = clampPan(current, current.x, nextY);
                      return {
                        ...current,
                        ...clamped,
                      };
                    });
                  }}
                  disabled={panLimits.maxY <= 0}
                />
              </label>
            </div>

            <div className="flex items-center justify-end gap-3 pt-1">
              <button
                type="button"
                onClick={closeCropEditor}
                disabled={uploading}
                className="px-4 py-2 rounded-md border border-gray-300 text-sm font-medium text-gray-700 hover:bg-gray-50 disabled:opacity-50"
              >
                Cancelar
              </button>
              <button
                type="button"
                onClick={handleApplyCrop}
                disabled={uploading}
                className="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-[var(--ks-color-primary)] text-white text-sm font-medium hover:opacity-95 disabled:opacity-50"
              >
                {uploading ? <Loader2 size={16} className="animate-spin" /> : null}
                Aplicar e enviar
              </button>
            </div>
          </div>
        </div>
      ) : null}
    </div>
  );
}
