"use client";

import { useRef, useState, type PointerEvent as ReactPointerEvent } from "react";
import { ImagePlus, Loader2, Maximize2, Minimize2, Trash2 } from "lucide-react";
import { NodeViewWrapper } from "@tiptap/react";
import type { NodeViewProps } from "@tiptap/react";
import { cn } from "@/lib/utils";
import type { ImageBlockOptions } from "./image-node";

interface ImageBlockViewProps extends NodeViewProps {
  options: ImageBlockOptions;
}

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

export function ImageBlockView({ node, updateAttributes, editor, deleteNode, options }: ImageBlockViewProps) {
  const src = node.attrs.src as string | null;
  const alt = (node.attrs.alt as string) || "";
  const width = (node.attrs.width as number) ?? 100;
  const fit = (node.attrs.fit as "cover" | "contain") ?? "cover";
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [liveWidth, setLiveWidth] = useState<number | null>(null);
  const liveWidthRef = useRef<number | null>(null);
  const editable = editor.isEditable;
  const displayWidth = liveWidth ?? width;

  function handleResizePointerDown(e: ReactPointerEvent<HTMLDivElement>) {
    if (!editable) return;
    const wrapper = e.currentTarget.closest("[data-image-wrapper]") as HTMLElement | null;
    const column = wrapper?.parentElement;
    if (!column) return;
    e.preventDefault();
    e.stopPropagation();

    const columnWidth = column.getBoundingClientRect().width;
    const startClientX = e.clientX;
    const startWidth = width;
    e.currentTarget.setPointerCapture(e.pointerId);

    function onMove(ev: PointerEvent) {
      const deltaPercent = ((ev.clientX - startClientX) / columnWidth) * 100;
      const next = clamp(startWidth + deltaPercent, 20, 100);
      liveWidthRef.current = next;
      setLiveWidth(next);
    }
    function onUp() {
      window.removeEventListener("pointermove", onMove);
      window.removeEventListener("pointerup", onUp);
      if (liveWidthRef.current) updateAttributes({ width: liveWidthRef.current });
      liveWidthRef.current = null;
      setLiveWidth(null);
    }
    window.addEventListener("pointermove", onMove);
    window.addEventListener("pointerup", onUp);
  }

  async function handleFile(file: File) {
    setUploading(true);
    setError(null);
    try {
      const formData = new FormData();
      formData.append("entityType", "note");
      formData.append("entityId", options.parentNoteId);
      formData.append("file", file);
      const res = await fetch("/api/attachments", { method: "POST", body: formData });
      const json = await res.json();
      if (!res.ok || !json.attachment) throw new Error(json.error || "Upload failed");
      updateAttributes({
        src: json.attachment.public_url as string,
        alt: file.name,
        attachmentId: json.attachment.id as string,
      });
    } catch (err) {
      setError(err instanceof Error ? err.message : "Upload failed");
    } finally {
      setUploading(false);
    }
  }

  if (!src) {
    return (
      <NodeViewWrapper className="my-3" contentEditable={false}>
        <div
          onClick={() => editable && !uploading && fileInputRef.current?.click()}
          className={cn(
            "flex flex-col items-center justify-center gap-2 rounded-2xl border border-dashed border-border bg-card/40 px-4 py-10 text-center transition-colors",
            editable ? "cursor-pointer hover:border-ring hover:bg-card/60" : "opacity-60",
          )}
        >
          {uploading ? (
            <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
          ) : (
            <ImagePlus className="h-5 w-5 text-muted-foreground" />
          )}
          <p className="text-[12.5px] font-medium text-muted-foreground">
            {uploading ? "Uploading…" : "Click to upload an image"}
          </p>
          {error && <p className="text-[11px] text-destructive">{error}</p>}
          <input
            ref={fileInputRef}
            type="file"
            accept="image/*"
            className="hidden"
            onChange={(e) => {
              const file = e.target.files?.[0];
              if (file) void handleFile(file);
              e.target.value = "";
            }}
          />
        </div>
      </NodeViewWrapper>
    );
  }

  return (
    <NodeViewWrapper className="my-3" contentEditable={false}>
      <div
        data-image-wrapper
        className="group relative"
        style={{ width: `${displayWidth}%`, touchAction: "none" }}
      >
        {/* eslint-disable-next-line @next/next/no-img-element */}
        <img
          src={src}
          alt={alt}
          className={cn(
            "max-h-[480px] w-full rounded-2xl border border-border bg-muted/30",
            fit === "cover" ? "object-cover" : "object-contain",
          )}
        />
        {editable && (
          <>
            <button
              type="button"
              onClick={() => deleteNode()}
              className="absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-lg bg-black/60 text-white opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100 hover:bg-black/80"
            >
              <Trash2 className="h-3.5 w-3.5" />
            </button>
            <button
              type="button"
              onClick={() => updateAttributes({ fit: fit === "cover" ? "contain" : "cover" })}
              title={fit === "cover" ? "Show full image (contain)" : "Fill frame (cover)"}
              className="absolute right-11 top-2 flex h-7 w-7 items-center justify-center rounded-lg bg-black/60 text-white opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100 hover:bg-black/80"
            >
              {fit === "cover" ? <Minimize2 className="h-3.5 w-3.5" /> : <Maximize2 className="h-3.5 w-3.5" />}
            </button>
            <div
              onPointerDown={handleResizePointerDown}
              title="Drag to resize"
              className="absolute -right-1.5 bottom-1.5 flex h-5 w-5 cursor-ew-resize items-center justify-center rounded-full border border-border bg-card opacity-0 shadow transition-opacity group-hover:opacity-100"
            >
              <div className="h-2 w-0.5 rounded-full bg-muted-foreground" />
            </div>
          </>
        )}
      </div>
    </NodeViewWrapper>
  );
}
