"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 || "";

    // 이미지 리사이즈 및 삭제 기능
    const setupImageHandlers = () => {
      const figures = el.querySelectorAll<HTMLElement>("figure[data-resizable='true']");
      figures.forEach((figure) => {
        // 리사이즈 핸들 설정
        const handle = figure.querySelector<HTMLElement>(".resize-handle");
        const img = figure.querySelector<HTMLImageElement>("img");
        if (handle && img) {
          // 기존 이벤트 리스너 제거 (중복 방지)
          const newHandle = handle.cloneNode(true) as HTMLElement;
          handle.parentNode?.replaceChild(newHandle, handle);

          let isResizing = false;
          let startX = 0;
          let startWidth = 0;

          const onMouseDown = (e: MouseEvent) => {
            e.preventDefault();
            e.stopPropagation();
            isResizing = true;
            startX = e.clientX;
            const rect = img.getBoundingClientRect();
            startWidth = rect.width;
            document.addEventListener("mousemove", onMouseMove);
            document.addEventListener("mouseup", onMouseUp);
          };

          const onMouseMove = (e: MouseEvent) => {
            if (!isResizing) return;
            const diffX = e.clientX - startX;
            const scale = Math.max(0.1, Math.min(3, 1 + (diffX / startWidth)));
            const newWidth = startWidth * scale;
            img.style.width = `${newWidth}px`;
            img.style.height = "auto";
            // onChange 동기화
            if (el) onChange(el.innerHTML);
          };

          const onMouseUp = () => {
            isResizing = false;
            document.removeEventListener("mousemove", onMouseMove);
            document.removeEventListener("mouseup", onMouseUp);
          };

          newHandle.addEventListener("mousedown", onMouseDown);
        }

        // 삭제 버튼 설정
        const deleteBtn = figure.querySelector<HTMLElement>(".delete-image-btn");
        if (deleteBtn) {
          // 기존 이벤트 리스너 제거 (중복 방지)
          const newDeleteBtn = deleteBtn.cloneNode(true) as HTMLElement;
          deleteBtn.parentNode?.replaceChild(newDeleteBtn, deleteBtn);

          const onDeleteClick = (e: MouseEvent) => {
            e.preventDefault();
            e.stopPropagation();
            if (figure.parentNode) {
              figure.parentNode.removeChild(figure);
              // onChange 동기화
              if (el) onChange(el.innerHTML);
            }
          };

          newDeleteBtn.addEventListener("click", onDeleteClick);
        }
      });
    };

    // 초기 설정 및 변경 감지
    setupImageHandlers();
    const observer = new MutationObserver(() => {
      setupImageHandlers();
    });
    observer.observe(el, { childList: true, subtree: true });

    return () => {
      observer.disconnect();
    };
  }, [value, onChange]);

  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 figure = `<figure style="margin:8px 0; position: relative; display: inline-block;" data-resizable="true"><img src="${data.url}" alt="" style="max-width: 100%; height: auto; display: block; cursor: pointer;" /><div class="resize-handle" style="position: absolute; bottom: 0; right: 0; width: 16px; height: 16px; background: #f94b37; cursor: se-resize; border-radius: 50% 0 0 0; opacity: 0.8;"></div><button class="delete-image-btn" style="position: absolute; top: 4px; right: 4px; width: 24px; height: 24px; background: rgba(0, 0, 0, 0.6); color: white; border: none; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 14px; line-height: 1; opacity: 0.8;" title="이미지 삭제">×</button></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-nowrap items-center gap-1 overflow-x-auto">
        <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-1 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100 flex items-center justify-center flex-shrink-0"
          onClick={() => exec("justifyLeft")}
          aria-label="왼쪽 정렬"
          style={{ width: "24px", height: "24px" }}
        >
          <span className="flex flex-col gap-0.5 items-start" style={{ width: "14px", height: "10px" }}>
            <span className="block h-0.5 bg-current" style={{ width: "10px" }} />
            <span className="block h-0.5 bg-current" style={{ width: "14px" }} />
            <span className="block h-0.5 bg-current" style={{ width: "10px" }} />
          </span>
        </button>
        <button
          type="button"
          className="px-1 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100 flex items-center justify-center flex-shrink-0"
          onClick={() => exec("justifyCenter")}
          aria-label="가운데 정렬"
          style={{ width: "24px", height: "24px" }}
        >
          <span className="flex flex-col gap-0.5 items-center" style={{ width: "14px", height: "10px" }}>
            <span className="block h-0.5 bg-current" style={{ width: "10px" }} />
            <span className="block h-0.5 bg-current" style={{ width: "14px" }} />
            <span className="block h-0.5 bg-current" style={{ width: "10px" }} />
          </span>
        </button>
        <button
          type="button"
          className="px-1 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100 flex items-center justify-center flex-shrink-0"
          onClick={() => exec("justifyRight")}
          aria-label="오른쪽 정렬"
          style={{ width: "24px", height: "24px" }}
        >
          <span className="flex flex-col gap-0.5 items-end" style={{ width: "14px", height: "10px" }}>
            <span className="block h-0.5 bg-current" style={{ width: "10px" }} />
            <span className="block h-0.5 bg-current" style={{ width: "14px" }} />
            <span className="block h-0.5 bg-current" style={{ width: "10px" }} />
          </span>
        </button>
        <button
          type="button"
          className="px-1 py-1 text-sm rounded border border-neutral-300 hover:bg-neutral-100 flex items-center justify-center flex-shrink-0"
          onClick={() => exec("justifyFull")}
          aria-label="양쪽 정렬"
          style={{ width: "24px", height: "24px" }}
        >
          <span className="flex flex-col gap-0.5 items-stretch" style={{ width: "14px", height: "10px" }}>
            <span className="block h-0.5 bg-current" style={{ width: "100%" }} />
            <span className="block h-0.5 bg-current" style={{ width: "100%" }} />
            <span className="block h-0.5 bg-current" style={{ width: "100%" }} />
          </span>
        </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,
          overflow: "auto",
        }}
        suppressContentEditableWarning
        className="[&_figure]:my-2 [&_figure]:block [&_figure_img]:max-w-full [&_figure_img]:h-auto [&_figure_img]:rounded-lg [&_figure_img]:border [&_figure_img]:border-neutral-200 [&_figure_img]:shadow-sm [&_figcaption]:mt-1 [&_figcaption]:text-xs [&_figcaption]:text-neutral-600 [&_figcaption]:text-center [&_img]:max-w-full [&_img]:h-auto [&_img]:rounded-lg [&_figure[data-resizable='true']]:hover_[.resize-handle]:opacity-100 [&_figure[data-resizable='true']_.resize-handle]:opacity-0 [&_figure[data-resizable='true']_.resize-handle]:transition-opacity [&_figure[data-resizable='true']]:hover_[.delete-image-btn]:opacity-100 [&_figure[data-resizable='true']_.delete-image-btn]:opacity-0 [&_figure[data-resizable='true']_.delete-image-btn]:transition-opacity"
      />
    </div>
  );
}


