"use client";

import {
  BoldOutlined,
  ItalicOutlined,
  LinkOutlined,
  OrderedListOutlined,
  PictureOutlined,
  UnorderedListOutlined,
  UploadOutlined,
} from "@ant-design/icons";
import Image from "@tiptap/extension-image";
import Link from "@tiptap/extension-link";
import Placeholder from "@tiptap/extension-placeholder";
import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import type { ChangeEvent, ReactNode } from "react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import "./rich-editor.css";

function apiBase(): string {
  return (process.env.NEXT_PUBLIC_API_BASE_URL ?? "").replace(/\/$/, "");
}

/** Chuẩn hoá URL người nhập: giữ nguyên http(s); đường dẫn site dùng dạng /... */
function normalizeImageUrlInput(raw: string): string {
  const t = raw.trim();
  if (!t) return t;
  if (t.startsWith("http://") || t.startsWith("https://")) return t;
  return t.startsWith("/") ? t : `/${t}`;
}

export type RichEditorProps = {
  value?: string;
  onChange?: (html: string) => void;
  disabled?: boolean;
};

function ToolbarDivider() {
  return (
    <span
      className="mx-0.5 hidden h-5 w-px shrink-0 self-center bg-slate-200/60 sm:block"
      aria-hidden
    />
  );
}

function ToolbarButton({
  active,
  disabled,
  title,
  onClick,
  children,
  className = "",
}: {
  active: boolean;
  disabled?: boolean;
  title: string;
  onClick: () => void;
  children: ReactNode;
  className?: string;
}) {
  return (
    <button
      type="button"
      title={title}
      disabled={disabled}
      onClick={onClick}
      className={
        "inline-flex h-8 shrink-0 items-center justify-center rounded-full text-[13px] font-medium transition-[color,background-color,box-shadow] duration-150 disabled:cursor-not-allowed disabled:opacity-40 " +
        (active
          ? "bg-slate-100 text-slate-900 ring-1 ring-slate-200/90 ring-inset"
          : "text-slate-500 hover:bg-slate-50 hover:text-slate-800") +
        (className ? ` ${className}` : "")
      }
    >
      {children}
    </button>
  );
}

export default function RichEditor({ value, onChange, disabled }: RichEditorProps) {
  const [mounted, setMounted] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = useState(false);
  const [uploadErr, setUploadErr] = useState<string | null>(null);
  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;

  useEffect(() => {
    setMounted(true);
  }, []);

  const extensions = useMemo(
    () => [
      StarterKit.configure({
        heading: { levels: [2, 3] },
      }),
      Link.configure({
        openOnClick: false,
        autolink: true,
        defaultProtocol: "https",
      }),
      Image.configure({
        inline: false,
        allowBase64: false,
      }),
      Placeholder.configure({
        placeholder: "Start writing…",
        showOnlyWhenEditable: true,
      }),
    ],
    [],
  );

  const editorProps = useMemo(
    () => ({
      attributes: {
        class:
          "tiptap rich-editor-prose max-w-none px-7 py-8 text-[17px] leading-[1.8] text-slate-800 antialiased outline-none sm:px-10 sm:py-10",
      },
    }),
    [],
  );

  const editor = useEditor({
    extensions,
    content: value ?? "",
    editable: !disabled,
    immediatelyRender: false,
    editorProps,
    onUpdate({ editor: ed }) {
      onChangeRef.current?.(ed.getHTML());
    },
  });

  useEffect(() => {
    if (!editor) return;
    editor.setEditable(!disabled);
  }, [disabled, editor]);

  useEffect(() => {
    if (!editor) return;
    const incoming = value ?? "";
    if (incoming === editor.getHTML()) return;
    editor.commands.setContent(incoming, { emitUpdate: false });
  }, [value, editor]);

  const uploadImageFile = useCallback(
    async (file: File) => {
      if (!editor) return;
      const token = typeof window !== "undefined" ? localStorage.getItem("accessToken") : null;
      if (!token) {
        setUploadErr("Cần đăng nhập để tải ảnh.");
        return;
      }
      const base = apiBase();
      if (!base) {
        setUploadErr("Chưa cấu hình NEXT_PUBLIC_API_BASE_URL.");
        return;
      }

      setUploading(true);
      setUploadErr(null);
      try {
        const fd = new FormData();
        fd.append("file", file);
        const res = await fetch(`${base}/media/upload`, {
          method: "POST",
          headers: { Authorization: `Bearer ${token}` },
          body: fd,
        });
        const body = (await res.json().catch(() => ({}))) as { url?: string; message?: string };
        if (!res.ok) {
          throw new Error(typeof body.message === "string" ? body.message : "Upload thất bại");
        }
        if (!body.url?.trim()) throw new Error("Upload thất bại");
        const src = body.url.trim().startsWith("/") ? body.url.trim() : `/${body.url.trim()}`;
        editor.chain().focus().setImage({ src, alt: "" }).run();
      } catch (e) {
        setUploadErr(e instanceof Error ? e.message : "Upload thất bại");
      } finally {
        setUploading(false);
      }
    },
    [editor],
  );

  const onFileChange = (e: ChangeEvent<HTMLInputElement>) => {
    const f = e.target.files?.[0];
    e.target.value = "";
    if (f) void uploadImageFile(f);
  };

  if (!mounted || !editor) {
    return (
      <div
        aria-hidden
        className="min-h-[360px] rounded-2xl border border-slate-200/90 bg-white shadow-[0_1px_2px_rgba(15,23,42,0.04),0_8px_24px_-8px_rgba(15,23,42,0.08)]"
      />
    );
  }

  return (
    <div
      className={`rich-editor-surface overflow-hidden rounded-2xl border border-slate-200/70 bg-white shadow-[0_1px_3px_rgba(15,23,42,0.04),0_12px_32px_-12px_rgba(15,23,42,0.07)] transition-[box-shadow,border-color] duration-200 focus-within:border-slate-300/75 focus-within:shadow-[0_1px_3px_rgba(15,23,42,0.05),0_16px_40px_-14px_rgba(15,23,42,0.1)] ${disabled ? "opacity-55" : ""}`}
    >
      <div className="flex flex-wrap items-center gap-1 border-b border-slate-100 bg-white px-3 py-2.5 sm:gap-1.5 sm:px-4">
        <ToolbarButton
          active={editor.isActive("bold")}
          disabled={disabled}
          title="Bold"
          onClick={() => editor.chain().focus().toggleBold().run()}
          className="min-w-8 px-0"
        >
          <BoldOutlined className="text-[15px]" />
        </ToolbarButton>
        <ToolbarButton
          active={editor.isActive("italic")}
          disabled={disabled}
          title="Italic"
          onClick={() => editor.chain().focus().toggleItalic().run()}
          className="min-w-8 px-0"
        >
          <ItalicOutlined className="text-[15px]" />
        </ToolbarButton>

        <ToolbarDivider />

        <ToolbarButton
          active={editor.isActive("heading", { level: 2 })}
          disabled={disabled}
          title="Heading 2"
          onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
          className="min-w-[2.25rem] px-2 font-semibold tracking-tight"
        >
          H2
        </ToolbarButton>
        <ToolbarButton
          active={editor.isActive("heading", { level: 3 })}
          disabled={disabled}
          title="Heading 3"
          onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
          className="min-w-[2.25rem] px-2 font-semibold tracking-tight"
        >
          H3
        </ToolbarButton>

        <ToolbarDivider />

        <ToolbarButton
          active={editor.isActive("bulletList")}
          disabled={disabled}
          title="Bullet list"
          onClick={() => editor.chain().focus().toggleBulletList().run()}
          className="min-w-8 px-0"
        >
          <UnorderedListOutlined className="text-[15px]" />
        </ToolbarButton>
        <ToolbarButton
          active={editor.isActive("orderedList")}
          disabled={disabled}
          title="Numbered list"
          onClick={() => editor.chain().focus().toggleOrderedList().run()}
          className="min-w-8 px-0"
        >
          <OrderedListOutlined className="text-[15px]" />
        </ToolbarButton>

        <ToolbarDivider />

        <ToolbarButton
          active={editor.isActive("link")}
          disabled={disabled}
          title="Link — empty URL removes link"
          onClick={() => {
            const prev = editor.getAttributes("link").href as string | undefined;
            const url = window.prompt("Link URL", prev ?? "https://");
            if (url === null) return;
            const trimmed = url.trim();
            if (trimmed === "") {
              editor.chain().focus().extendMarkRange("link").unsetLink().run();
              return;
            }
            editor.chain().focus().extendMarkRange("link").setLink({ href: trimmed }).run();
          }}
          className="min-w-8 px-0"
        >
          <LinkOutlined className="text-[15px]" />
        </ToolbarButton>

        <ToolbarDivider />

        <input
          ref={fileInputRef}
          type="file"
          accept="image/jpeg,image/png,image/gif,image/webp"
          className="sr-only"
          disabled={disabled || uploading}
          aria-label="Tải ảnh lên"
          onChange={onFileChange}
        />
        <ToolbarButton
          active={false}
          disabled={disabled || uploading}
          title="Tải ảnh lên"
          onClick={() => fileInputRef.current?.click()}
          className="min-w-8 px-0"
        >
          <UploadOutlined className="text-[15px]" />
        </ToolbarButton>
        <ToolbarButton
          active={editor.isActive("image")}
          disabled={disabled}
          title="Chèn ảnh từ URL"
          onClick={() => {
            const src = window.prompt("URL ảnh (https://… hoặc /uploads/…)", "https://");
            if (src === null) return;
            const trimmed = src.trim();
            if (!trimmed) return;
            editor.chain().focus().setImage({ src: normalizeImageUrlInput(trimmed), alt: "" }).run();
          }}
          className="min-w-8 px-0"
        >
          <PictureOutlined className="text-[15px]" />
        </ToolbarButton>
      </div>

      {uploading ? (
        <p className="border-b border-slate-100 px-4 py-2 text-xs text-slate-500">Đang tải ảnh…</p>
      ) : null}
      {uploadErr ? (
        <p className="border-b border-slate-100 px-4 py-2 text-xs text-red-600" role="alert">
          {uploadErr}
        </p>
      ) : null}

      <div
        className="min-h-[min(380px,44vh)] sm:min-h-[min(400px,48vh)] [&_.ProseMirror]:min-h-[min(340px,40vh)] sm:[&_.ProseMirror]:min-h-[min(380px,44vh)] [&_a]:text-sky-700 [&_a]:underline [&_a]:decoration-sky-600/30 [&_a]:underline-offset-[3px] [&_a]:transition-colors hover:[&_a]:decoration-sky-600/55 [&_h2]:mb-2 [&_h2]:mt-9 [&_h2]:scroll-mt-4 [&_h2]:text-2xl [&_h2]:font-semibold [&_h2]:tracking-tight [&_h2]:text-slate-900 [&_h2]:first:mt-0 [&_h3]:mb-2 [&_h3]:mt-7 [&_h3]:scroll-mt-4 [&_h3]:text-[1.25rem] [&_h3]:font-semibold [&_h3]:tracking-tight [&_h3]:text-slate-800 [&_h3]:first:mt-0 [&_img]:my-4 [&_img]:block [&_img]:h-auto [&_img]:max-h-[min(520px,70vh)] [&_img]:w-full [&_img]:max-w-full [&_img]:rounded-lg [&_img]:border [&_img]:border-slate-200/80 [&_img]:object-contain [&_img]:shadow-sm [&_img.ProseMirror-selectednode]:ring-2 [&_img.ProseMirror-selectednode]:ring-sky-300/80 [&_li]:my-0.5 [&_li]:pl-0.5 [&_li>p]:my-0 [&_ol]:my-3 [&_ol]:list-decimal [&_ol]:space-y-1.5 [&_ol]:pl-7 [&_ol]:text-slate-800 [&_p]:my-0 [&_p]:py-[0.45rem] [&_p:first-child]:pt-0 [&_ul]:my-3 [&_ul]:list-disc [&_ul]:space-y-1.5 [&_ul]:pl-7 [&_ul]:text-slate-800"
      >
        <EditorContent editor={editor} />
      </div>
    </div>
  );
}
