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

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

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, withToolbar = true }: 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]
  );

  const sync = useCallback(() => {
    const el = ref.current;
    if (el) onChange(el.innerHTML);
  }, [onChange]);

  const exec = useCallback(
    (command: string, value?: string) => {
      const el = ref.current;
      if (!el) return;
      el.focus();
      try {
        // eslint-disable-next-line deprecation/deprecation
        document.execCommand(command, false, value ?? "");
      } catch {
        /* no-op */
      }
      sync();
    },
    [sync]
  );

  const wrapSelectionWithHtml = useCallback(
    (prefix: string, suffix: string) => {
      const selection = window.getSelection();
      const text = selection?.toString() ?? "";
      if (!text) return;
      // eslint-disable-next-line deprecation/deprecation
      document.execCommand("insertHTML", false, `${prefix}${text}${suffix}`);
      sync();
    },
    [sync]
  );

  const toolbar = useMemo(() => {
    if (!withToolbar) return null;
    return (
      <div className="flex flex-wrap items-center gap-1">
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("bold")} aria-label="굵게">B</button>
        <button type="button" className="px-2 py-1 text-sm italic rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("italic")} aria-label="기울임">I</button>
        <button type="button" className="px-2 py-1 text-sm line-through rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("strikeThrough")} aria-label="취소선">S</button>
        <button type="button" className="px-2 py-1 text-sm underline rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("underline")} aria-label="밑줄">U</button>
        <button
          type="button"
          className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100"
          onClick={() => {
            const url = window.prompt("링크 URL 입력 (예: https://example.com)")?.trim();
            if (url) exec("createLink", url);
          }}
          aria-label="링크"
        >
          link
        </button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("unlink")} aria-label="링크 제거">unlink</button>
        <span className="mx-2 h-4 w-px bg-neutral-300" />
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("formatBlock", "H1")} aria-label="H1">H1</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("formatBlock", "H2")} aria-label="H2">H2</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("formatBlock", "H3")} aria-label="H3">H3</button>
        <span className="mx-2 h-4 w-px bg-neutral-300" />
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("insertOrderedList")} aria-label="번호 목록">1.</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("insertUnorderedList")} aria-label="글머리 목록">•</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => wrapSelectionWithHtml("<code>", "</code>")} aria-label="코드">&lt;/&gt;</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("formatBlock", "BLOCKQUOTE")} aria-label="인용구">❝</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("insertHorizontalRule")} aria-label="구분선">—</button>
        <span className="mx-2 h-4 w-px bg-neutral-300" />
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("justifyLeft")} aria-label="왼쪽 정렬">⟸</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("justifyCenter")} aria-label="가운데 정렬">⟷</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("justifyRight")} aria-label="오른쪽 정렬">⟹</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("justifyFull")} aria-label="양쪽 정렬">≋</button>
        <span className="mx-2 h-4 w-px bg-neutral-300" />
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("indent")} aria-label="들여쓰기">⇥</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("outdent")} aria-label="내어쓰기">⇤</button>
        <span className="mx-2 h-4 w-px bg-neutral-300" />
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("removeFormat")} aria-label="서식 제거">clear</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("undo")} aria-label="되돌리기">↶</button>
        <button type="button" className="px-2 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100" onClick={() => exec("redo")} aria-label="다시하기">↷</button>
      </div>
    );
  }, [exec, withToolbar, wrapSelectionWithHtml]);

  return (
    <div>
      {toolbar && (
        <div className="mb-3">{toolbar}</div>
      )}
      <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
      />
    </div>
  );
}


