"use client";
import { useEffect, useRef, useCallback } from "react";
import { useToast } from "@/app/components/ui/ToastProvider";

type Props = { value: string; onChange: (v: string) => void; placeholder?: string };

async function readFileAsDataUrl(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result));
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

async function resizeImageToBlob(dataUrl: string, opts: { maxWidth: number; maxHeight: number; quality: number }): Promise<Blob> {
  const img = document.createElement("img");
  img.decoding = "async";
  img.loading = "eager";
  img.src = dataUrl;
  await new Promise((res, rej) => {
    img.onload = () => res(null);
    img.onerror = rej;
  });
  const w = img.naturalWidth || 1;
  const h = img.naturalHeight || 1;
  const scale = Math.min(1, opts.maxWidth / w || 1, opts.maxHeight / h || 1);
  const targetW = Math.max(1, Math.round(w * scale));
  const targetH = Math.max(1, Math.round(h * scale));
  const canvas = document.createElement("canvas");
  canvas.width = targetW;
  canvas.height = targetH;
  const ctx = canvas.getContext("2d");
  if (!ctx) throw new Error("Canvas unsupported");
  ctx.drawImage(img, 0, 0, targetW, targetH);
  return await new Promise((resolve) => canvas.toBlob((b) => resolve(b as Blob), "image/webp", opts.quality));
}

export function Editor({ value, onChange, placeholder }: Props) {
  const ref = useRef<HTMLDivElement | null>(null);
  const { show } = useToast();

  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    if (el.innerHTML !== value) el.innerHTML = value || "";
  }, [value]);

  const insertHtmlAtCursor = useCallback((html: string) => {
    // eslint-disable-next-line deprecation/deprecation
    document.execCommand("insertHTML", false, html);
  }, []);

  const uploadAndInsert = useCallback(
    async (files: File[]) => {
      const images = files.filter((f) => f.type.startsWith("image/"));
      if (images.length === 0) return;
      for (const f of images) {
        try {
          const dataUrl = await readFileAsDataUrl(f);
          const blob = await resizeImageToBlob(dataUrl, { maxWidth: 1600, maxHeight: 1600, quality: 0.9 });
          const fd = new FormData();
          fd.append("file", new File([blob], `${Date.now()}.webp`, { type: "image/webp" }));
          const r = await fetch("/api/uploads", { method: "POST", body: fd });
          const data = await r.json();
          if (!r.ok) throw new Error(JSON.stringify(data));
          const alt = window.prompt("이미지 대체텍스트(ALT)를 입력하세요.") || "";
          const caption = window.prompt("이미지 캡션(선택)") || "";
          const figure = `<figure style="margin:8px 0"><img src="${data.url}" alt="${alt.replace(/"/g, '&quot;')}" /><figcaption style="font-size:12px;opacity:.8">${caption.replace(/</g, "&lt;")}</figcaption></figure>`;
          insertHtmlAtCursor(figure);
          // onChange 동기화
          const el = ref.current;
          if (el) onChange(el.innerHTML);
        } catch {
          show("이미지 업로드 실패");
        }
      }
    },
    [insertHtmlAtCursor, onChange, show]
  );

  const onPaste = useCallback(
    async (e: React.ClipboardEvent<HTMLDivElement>) => {
      const files = Array.from(e.clipboardData?.files ?? []);
      if (files.some((f) => f.type.startsWith("image/"))) {
        e.preventDefault();
        await uploadAndInsert(files);
      }
    },
    [uploadAndInsert]
  );

  const onDrop = useCallback(
    async (e: React.DragEvent<HTMLDivElement>) => {
      e.preventDefault();
      const files = Array.from(e.dataTransfer?.files ?? []);
      if (files.length > 0) await uploadAndInsert(files);
    },
    [uploadAndInsert]
  );

  return (
    <div
      ref={ref}
      contentEditable
      onInput={(e) => onChange((e.target as HTMLDivElement).innerHTML)}
      onPaste={onPaste}
      onDrop={onDrop}
      onDragOver={(e) => e.preventDefault()}
      data-placeholder={placeholder}
      style={{
        minHeight: 160,
        border: "1px solid #ddd",
        borderRadius: 6,
        padding: 12,
      }}
      suppressContentEditableWarning
    />
  );
}


