import { Extension } from '@tiptap/core';
import Highlight from '@tiptap/extension-highlight';
import Image from '@tiptap/extension-image';
import Link from '@tiptap/extension-link';
import Paragraph from '@tiptap/extension-paragraph';
import Placeholder from '@tiptap/extension-placeholder';
import Subscript from '@tiptap/extension-subscript';
import Superscript from '@tiptap/extension-superscript';
import { TableKit } from '@tiptap/extension-table';
import TaskItem from '@tiptap/extension-task-item';
import TaskList from '@tiptap/extension-task-list';
import TextAlign from '@tiptap/extension-text-align';
import {
    Color,
    FontFamily,
    FontSize,
    TextStyle,
} from '@tiptap/extension-text-style';
import Typography from '@tiptap/extension-typography';
import Underline from '@tiptap/extension-underline';
import { EditorContent, useEditor, useEditorState } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import {
    AlignCenter,
    AlignJustify,
    AlignLeft,
    AlignRight,
    ArrowDownToLine,
    GripVertical,
    ArrowLeftFromLine,
    ArrowRightToLine,
    ArrowUpFromLine,
    Bold,
    Check,
    ChevronDown,
    ChevronsUpDown,
    Code2,
    Eraser,
    Heading1,
    Heading2,
    Heading3,
    Highlighter,
    ImagePlus,
    Images,
    Italic,
    Link as LinkIcon,
    List,
    ListChecks,
    ListOrdered,
    Loader2,
    Minus,
    Palette,
    Pilcrow,
    Quote,
    Redo2,
    SquareCode,
    Strikethrough,
    Subscript as SubscriptIcon,
    Superscript as SuperscriptIcon,
    Table2,
    Trash2,
    Type,
    Underline as UnderlineIcon,
    Undo2,
    Unlink,
} from 'lucide-react';
import { useEffect, useId, useRef, useState } from 'react';
import type { ChangeEvent, ReactNode } from 'react';
import { MediaPickerDialog } from '@/components/admin/media-picker-dialog';
import type { MediaPickerItem } from '@/components/admin/media-picker-dialog';
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuSeparator,
    DropdownMenuShortcut,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { compressImage, isCompressibleImage } from '@/lib/compress-image';
import { cn } from '@/lib/utils';
import { editorUpload } from '@/routes/admin/media';

type Props = {
    value: string;
    onChange: (html: string) => void;
    placeholder?: string;
    label?: string;
    /** Bahasa aktif tab (id/en) — dipakai untuk alt text gambar dari Library. */
    locale?: string;
};

type ToolbarButtonProps = {
    onClick: () => void;
    active?: boolean;
    label: string;
    /** Pintasan keyboard — ditampilkan di tooltip, mis. "Tebal (Ctrl+B)". */
    shortcut?: string;
    children: ReactNode;
    disabled?: boolean;
};

function ToolbarButton({
    onClick,
    active = false,
    label,
    shortcut,
    children,
    disabled,
}: ToolbarButtonProps) {
    const hint = shortcut ? `${label} (${shortcut})` : label;

    return (
        <button
            type="button"
            title={hint}
            aria-label={hint}
            aria-pressed={active}
            disabled={disabled}
            onClick={onClick}
            className={cn(
                'flex size-8 items-center justify-center rounded-md transition-colors',
                active
                    ? 'bg-primary text-primary-foreground'
                    : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                disabled &&
                    'cursor-not-allowed opacity-40 hover:bg-transparent hover:text-muted-foreground',
            )}
        >
            {children}
        </button>
    );
}

function Divider() {
    return <div className="mx-1 h-5 w-px bg-border" />;
}

const FONT_SIZES = [
    { value: '12px', label: '12' },
    { value: '14px', label: '14' },
    { value: '16px', label: '16' },
    { value: '18px', label: '18' },
    { value: '20px', label: '20' },
    { value: '24px', label: '24' },
    { value: '28px', label: '28' },
    { value: '32px', label: '32' },
    { value: '36px', label: '36' },
] as const;

const FONT_FAMILIES = [
    { value: 'Poppins', label: 'Poppins (default)' },
    { value: 'Arial, sans-serif', label: 'Arial' },
    { value: 'Georgia, serif', label: 'Georgia' },
    { value: 'sans-serif', label: 'Sans Serif' },
    { value: 'serif', label: 'Serif' },
    { value: 'monospace', label: 'Monospace' },
] as const;

// Gaya marker daftar nomor — nilai atribut HTML `type` pada <ol>.
// `short` = label tombol di toolbar, `title` = tooltip lengkap.
const LIST_STYLES = [
    { value: '1', short: '1.', title: 'Angka (1. 2. 3.)' },
    { value: 'a', short: 'a.', title: 'Huruf kecil (a. b. c.)' },
    { value: 'A', short: 'A.', title: 'Huruf besar (A. B. C.)' },
    { value: 'i', short: 'i.', title: 'Romawi kecil (i. ii. iii.)' },
    { value: 'I', short: 'I.', title: 'Romawi besar (I. II. III.)' },
] as const;

// Pemetaan nilai atribut `type` → CSS list-style-type.
const LIST_STYLE_CSS: Record<string, string> = {
    '1': 'decimal',
    a: 'lower-alpha',
    A: 'upper-alpha',
    i: 'lower-roman',
    I: 'upper-roman',
};

// Ukuran gambar preset — lebar dalam persen (dari parent).
const IMAGE_SIZES = [
    { value: '25', label: '25%' },
    { value: '50', label: '50%' },
    { value: '75', label: '75%' },
    { value: '100', label: '100%' },
] as const;

// Atribut `type` pada <ol> di-matching case-insensitively oleh browser
// (whatwg/html#4158) — `<ol type="a">` bisa ter-render sebagai A. B. C. di
// Chrome. Karena itu `data-list-style` (data attribute case-sensitive) ditulis
// sebagai sumber kebenaran CSS yang deterministik.
//
// Diterapkan lewat *global attribute* pada node `orderedList` bawaan StarterKit
// — TANPA import `@tiptap/extension-list` langsung. Import langsung membuat dua
// instance modul di pre-bundle Vite (StarterKit membundel copy-nya sendiri di
// chunk terpisah) sehingga memicu RangeError "Adding different instances of a
// keyed plugin".
const OrderedListStyle = Extension.create({
    name: 'orderedListStyle',
    addGlobalAttributes() {
        return [
            {
                types: ['orderedList'],
                attributes: {
                    listStyleType: {
                        default: null,
                        parseHTML: (element) =>
                            element.getAttribute('data-list-style'),
                        renderHTML: (attributes) =>
                            attributes.listStyleType
                                ? {
                                      'data-list-style':
                                          attributes.listStyleType,
                                  }
                                : {},
                    },
                },
            },
        ];
    },
});

// Extend Image node agar atribut dataAlign & dataWidth menjadi bagian
// dari schema — ini memastikan getHTML() ikut serialize atribut ini.
const ImageWithAlign = Image.extend({
    addAttributes() {
        return {
            ...this.parent?.(),
            dataAlign: {
                default: null,
                parseHTML: (element) => element.getAttribute('data-align'),
                renderHTML: (attributes) =>
                    attributes.dataAlign
                        ? { 'data-align': attributes.dataAlign }
                        : {},
            },
            dataWidth: {
                default: null,
                parseHTML: (element) => element.getAttribute('data-width'),
                renderHTML: (attributes) =>
                    attributes.dataWidth
                        ? { 'data-width': attributes.dataWidth }
                        : {},
            },
        };
    },
});

const DEFAULT_TOOLBAR = {
    bold: false,
    italic: false,
    underline: false,
    strike: false,
    sub: false,
    sup: false,
    h1: false,
    h2: false,
    h3: false,
    paragraph: true,
    bullet: false,
    ordered: false,
    orderedListType: '1' as string,
    task: false,
    quote: false,
    code: false,
    codeBlock: false,
    link: false,
    alignLeft: false,
    alignCenter: false,
    alignRight: false,
    alignJustify: false,
    textStyle: {} as Record<string, unknown>,
    highlight: false,
    table: false,
    canUndo: false,
    canRedo: false,
    lineHeight: null as string | null,
};

/**
 * Paragraph dengan atribut `lineHeight` per blok — diatur tombol spasi
 * (panah atas/bawah) di toolbar. Disimpan inline style agar portable
 * ke render frontend (tiptap-content) tanpa plugin tambahan.
 */
const ParagraphWithLineHeight = Paragraph.extend({
    addAttributes() {
        return {
            ...this.parent?.(),
            lineHeight: {
                default: null,
                parseHTML: (el: HTMLElement) => el.style.lineHeight || null,
                renderHTML: (attrs: Record<string, unknown>) =>
                    attrs.lineHeight ? { style: `line-height: ${attrs.lineHeight}` } : {},
            },
        };
    },
});

// Preset spasi baris — gaya MS Office.
const LINE_HEIGHT_OPTIONS = ['1.0', '1.15', '1.5', '1.75', '2.0', '2.5'];

type ToolbarState = typeof DEFAULT_TOOLBAR;

// CSRF token dari cookie XSRF-TOKEN (Laravel + Inertia).
function getXsrfToken(): string {
    const match = document.cookie.match(/(?:^|; )XSRF-TOKEN=([^;]+)/);

    return match ? decodeURIComponent(match[1]) : '';
}

/**
 * Editor konten panjang (Tiptap v3) — toolbar lengkap: format teks, heading,
 * warna, ukuran/jenis font, list (bullet/nomor/task), tabel, gambar (upload +
 * resize), tautan, perataan, dan lainnya. HTML output disanitasi server-side
 * (mews/purifier) sebelum disimpan (docs-ai/06 §4.5).
 */
export default function RichTextEditor({
    value,
    onChange,
    placeholder,
    label,
    locale = 'id',
}: Props) {
    const fileInputRef = useRef<HTMLInputElement>(null);
    // Sufiks unik untuk id input warna/sorot — mencegah duplikat id bila ada
    // lebih dari satu editor di halaman (HeroForm, AboutSectionForm, dll).
    const pickerId = useId();
    const [uploading, setUploading] = useState(false);
    const [pickerOpen, setPickerOpen] = useState(false);
    const [imageToolbarPos, setImageToolbarPos] = useState<{ top: number; left: number } | null>(null);
    const imageToolbarRef = useRef<HTMLDivElement>(null);

    // Drag-to-resize state
    const DEFAULT_HEIGHT = 300;
    const [editorHeight, setEditorHeight] = useState(DEFAULT_HEIGHT);
    const isDragging = useRef(false);
    const startY = useRef(0);
    const startHeight = useRef(0);

    const onResizeMouseDown = (e: React.MouseEvent) => {
        e.preventDefault();
        isDragging.current = true;
        startY.current = e.clientY;
        startHeight.current = editorHeight;

        const onMouseMove = (ev: MouseEvent) => {
            if (!isDragging.current) {
return;
}

            const delta = ev.clientY - startY.current;
            setEditorHeight(Math.max(150, startHeight.current + delta));
        };

        const onMouseUp = () => {
            isDragging.current = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
            document.body.style.cursor = '';
            document.body.style.userSelect = '';
        };

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);
        document.body.style.cursor = 'ns-resize';
        document.body.style.userSelect = 'none';
    };

    const editor = useEditor({
        extensions: [
            // StarterKit v3 sudah include Link, Underline & OrderedList —
            // nonaktifkan Link & Underline agar tidak duplikat dengan konfigurasi
            // eksplisit di bawah (autolink kita). OrderedList bawaan dipakai
            // langsung; gaya marker (a. b. c.) di-set via atribut global
            // OrderedListStyle di atas.
            StarterKit.configure({ link: false, underline: false, paragraph: false }),
            ParagraphWithLineHeight,
            OrderedListStyle,
            Underline,
            Link.configure({
                openOnClick: false,
                autolink: true,
                HTMLAttributes: {
                    rel: 'noopener noreferrer',
                    target: '_blank',
                },
            }),
            Placeholder.configure({
                placeholder: placeholder ?? 'Tulis di sini...',
            }),
            Typography,
            TextAlign.configure({ types: ['heading', 'paragraph'] }),
            // Style teks: warna, jenis font, ukuran font (butuh TextStyle sebagai basis).
            TextStyle,
            Color,
            FontFamily,
            FontSize,
            Subscript,
            Superscript,
            Highlight.configure({ multicolor: true }),
            TaskList,
            TaskItem.configure({ nested: true }),
            // Tabel lengkap: header, sel, baris/kolom.
            TableKit,
            // Gambar dengan resize + alignment (extend Image langsung).
            ImageWithAlign.configure({
                resize: {
                    enabled: true,
                    minWidth: 60,
                    minHeight: 40,
                    alwaysPreserveAspectRatio: true,
                },
                HTMLAttributes: { class: 'rounded-md border' },
            }),
        ],
        content: value || '',
        immediatelyRender: false,
        editorProps: {
            attributes: {
                class: 'prose-sm h-full max-w-none px-3 py-2 text-sm focus:outline-none [&_h2]:mb-2 [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:mb-1.5 [&_h3]:text-base [&_h3]:font-semibold [&_p]:my-1.5 [&_a]:text-primary [&_a]:underline [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:pl-5 [&_blockquote]:my-2 [&_blockquote]:border-l-2 [&_blockquote]:pl-3 [&_blockquote]:italic [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:font-mono [&_code]:text-xs [&_pre]:my-2 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-muted [&_pre]:p-3 [&_pre_code]:bg-transparent [&_hr]:my-3 [&_table]:w-full [&_table]:border-collapse [&_td]:border [&_td]:p-2 [&_th]:border [&_th]:p-2 [&_th]:font-semibold [&_img]:max-w-full [&_img]:h-auto',
            },
        },
        onUpdate: ({ editor: current }) => onChange(current.getHTML()),
    });

    // State toolbar — re-render saat seleksi berubah (posisi kursor, mark aktif).
    const toolbar =
        useEditorState({
            editor,
            selector: ({ editor: current }): ToolbarState => {
                if (!current) {
                    return DEFAULT_TOOLBAR;
                }

                const textStyle = current.getAttributes('textStyle') as Record<
                    string,
                    unknown
                >;

                return {
                    bold: current.isActive('bold'),
                    italic: current.isActive('italic'),
                    underline: current.isActive('underline'),
                    strike: current.isActive('strike'),
                    sub: current.isActive('subscript'),
                    sup: current.isActive('superscript'),
                    h1: current.isActive('heading', { level: 1 }),
                    h2: current.isActive('heading', { level: 2 }),
                    h3: current.isActive('heading', { level: 3 }),
                    paragraph: !current.isActive('heading'),
                    bullet: current.isActive('bulletList'),
                    ordered: current.isActive('orderedList'),
                    orderedListType:
                        (current.getAttributes('orderedList').type as
                            string | null | undefined) || '1',
                    task: current.isActive('taskList'),
                    quote: current.isActive('blockquote'),
                    code: current.isActive('code'),
                    codeBlock: current.isActive('codeBlock'),
                    link: current.isActive('link'),
                    alignLeft: current.isActive({ textAlign: 'left' }),
                    alignCenter: current.isActive({ textAlign: 'center' }),
                    alignRight: current.isActive({ textAlign: 'right' }),
                    alignJustify: current.isActive({ textAlign: 'justify' }),
                    textStyle,
                    highlight: current.isActive('highlight'),
                    table: current.isActive('table'),
                    canUndo: current.can().undo(),
                    canRedo: current.can().redo(),
                    lineHeight: (current.getAttributes('paragraph').lineHeight as string | null) ?? null,
                };
            },
        }) ?? DEFAULT_TOOLBAR;

    // Sinkronkan konten saat value berubah dari luar (ganti bahasa, reset, load edit).
    useEffect(() => {
        if (!editor) {
            return;
        }

        const next = value || '';

        if (editor.getHTML() !== next) {
            editor.commands.setContent(next, { emitUpdate: false });
        }
    }, [editor, value]);

    // Pantau seleksi gambar — tampilkan floating toolbar saat gambar diklik.
    // Deteksi pakai isActive('image') karena ResizableNodeView bisa mengubah
    // struktur DOM sehingga nodeAt(from) tidak selalu return node image.
    const [, setIsImageSelected] = useState(false);

    useEffect(() => {
        if (!editor) {
            return;
        }

        const updateImageToolbar = () => {
            const active = editor.isActive('image');
            setIsImageSelected(active);

            if (!active) {
                setImageToolbarPos(null);

                return;
            }

            // Cari elemen DOM gambar dari editor.
            // ResizableNodeView membungkus img di dalam [data-resize-container].
            const imgEl = editor.view.dom.querySelector('.ProseMirror-selectednode img')
                ?? editor.view.dom.querySelector('[data-resize-container] img');

            if (!imgEl) {
                setImageToolbarPos(null);

                return;
            }

            const imgRect = imgEl.getBoundingClientRect();
            const editorRect = editor.view.dom.getBoundingClientRect();
            setImageToolbarPos({
                top: imgRect.top - editorRect.top - 44,
                left: imgRect.left - editorRect.left,
            });
        };

        editor.on('selectionUpdate', updateImageToolbar);
        editor.on('transaction', updateImageToolbar);

        return () => {
            editor.off('selectionUpdate', updateImageToolbar);
            editor.off('transaction', updateImageToolbar);
        };
    }, [editor]);

    // Update atribut gambar (align / width) — tanpa setNodeSelection
    // untuk menghindari konflik dengan ResizableNodeView.
    const updateSelectedImage = (attrs: Record<string, unknown>) => {
        if (!editor || !editor.isActive('image')) {
            return;
        }

        editor.chain().focus().updateAttributes('image', attrs).run();
    };

    // Ambil atribut gambar yang sedang dipilih.
    const selectedImageAlign = editor?.getAttributes('image').dataAlign as string | null | undefined ?? null;
    const selectedImageWidth = editor?.getAttributes('image').dataWidth as string | null | undefined ?? null;

    const setLink = () => {
        if (!editor) {
            return;
        }

        const previous = editor.getAttributes('link').href as
            string | undefined;
        const url = window.prompt('URL link:', previous ?? 'https://');

        if (url === null) {
            return;
        }

        if (url === '') {
            editor.chain().focus().extendMarkRange('link').unsetLink().run();

            return;
        }

        editor
            .chain()
            .focus()
            .extendMarkRange('link')
            .setLink({ href: url })
            .run();
    };

    const setFontFamily = (value: string) => {
        if (!editor) {
            return;
        }

        if (value === '') {
            editor.chain().focus().unsetFontFamily().run();
        } else {
            editor.chain().focus().setFontFamily(value).run();
        }
    };

    const setFontSize = (value: string) => {
        if (!editor) {
            return;
        }

        if (value === '') {
            editor.chain().focus().unsetFontSize().run();
        } else {
            editor.chain().focus().setFontSize(value).run();
        }
    };

    /**
     * Gaya marker daftar nomor (1. / a. / A. / i. / I.) — di-set lewat atribut
     * HTML `type` pada node orderedList (`<ol type="a">`).
     */
    const setOrderedListStyle = (value: string) => {
        if (!editor) {
            return;
        }

        const css = LIST_STYLE_CSS[value] ?? 'decimal';

        if (value === '1') {
            // Kembali ke angka default: buat list bila belum ada, atau reset type.
            if (editor.isActive('orderedList')) {
                editor
                    .chain()
                    .focus()
                    .updateAttributes('orderedList', {
                        type: null,
                        listStyleType: null,
                    })
                    .run();
            } else {
                editor.chain().focus().toggleOrderedList().run();
            }

            return;
        }

        if (editor.isActive('orderedList')) {
            editor
                .chain()
                .focus()
                .updateAttributes('orderedList', {
                    type: value,
                    listStyleType: css,
                })
                .run();
        } else {
            editor
                .chain()
                .focus()
                .toggleOrderedList()
                .updateAttributes('orderedList', {
                    type: value,
                    listStyleType: css,
                })
                .run();
        }
    };

    const handleImageFile = async (event: ChangeEvent<HTMLInputElement>) => {
        const file = event.target.files?.[0];
        event.target.value = '';

        if (!file || !editor) {
            return;
        }

        setUploading(true);

        try {
            // Kompresi gambar sebelum upload.
            let fileToUpload = file;

            if (isCompressibleImage(file)) {
                try {
                    const result = await compressImage(file, {
                        quality: 0.8,
                        maxDimension: 1920,
                    });
                    fileToUpload = result.file;
                } catch {
                    // Fallback: upload file asli.
                }
            }

            const formData = new FormData();
            formData.append('file', fileToUpload);
            formData.append('collection', 'editor');

            const response = await fetch(editorUpload.url(), {
                method: 'POST',
                headers: {
                    Accept: 'application/json',
                    'X-XSRF-TOKEN': getXsrfToken(),
                },
                body: formData,
            });

            if (!response.ok) {
                throw new Error(`Upload gagal (${response.status})`);
            }

            const data = (await response.json()) as { url: string };

            editor.chain().focus().setImage({ src: data.url, alt: '' }).run();
        } catch (error) {
            console.error('Gagal mengunggah gambar:', error);
            window.alert(
                'Gagal mengunggah gambar. Pastikan file berupa PNG/JPG/WEBP (maks. 8 MB).',
            );
        } finally {
            setUploading(false);
        }
    };

    /**
     * Pilih gambar dari Library Media → sisipkan ke editor (URL + alt dari media).
     * Mode multi: semua gambar terpilih disisipkan berurutan di posisi kursor.
     *
     * Setiap item disisipkan di posisi kursor *saat itu*, lalu kursor dipindah ke
     * akhir konten yang baru disisipkan agar gambar berikutnya tidak menimpa
     * gambar sebelumnya (insertContent memakai selection aktif).
     */
    const handlePickFromLibrary = (
        media: MediaPickerItem | MediaPickerItem[],
    ) => {
        if (!editor) {
            return;
        }

        const items = Array.isArray(media) ? media : [media];

        if (items.length === 0) {
            return;
        }

        items.forEach((item, index) => {
            // Alt text mengikuti bahasa tab aktif (id/en) — fallback ke bahasa
            // lain bila bahasa aktif kosong, lalu nama file.
            const alt =
                item.alt[locale as keyof typeof item.alt] ||
                (locale === 'id' ? item.alt.en : item.alt.id) ||
                item.name;

            editor
                .chain()
                .focus()
                .insertContent({
                    type: 'image',
                    attrs: { src: item.url, alt },
                })
                .run();

            // Pindahkan kursor ke akhir dokumen setelah gambar disisipkan agar
            // gambar berikutnya berurutan, bukan menimpa posisi kursor lama.
            editor.chain().focus('end').run();

            // Pemisah antar gambar agar tidak menempel.
            if (index < items.length - 1) {
                editor
                    .chain()
                    .focus('end')
                    .insertContent({ type: 'paragraph' })
                    .run();
            }
        });

        editor.chain().focus('end').run();
    };

    const insertTable = () => {
        editor
            ?.chain()
            .focus()
            .insertTable({ rows: 3, cols: 3, withHeaderRow: true })
            .run();
    };

    const deleteTable = () => {
        editor?.chain().focus().deleteTable().run();
    };

    const clearFormatting = () => {
        editor?.chain().focus().unsetAllMarks().clearNodes().run();
    };

    // Set line-height paragraf aktif dari preset dropdown.
    const setLineHeight = (value: string) => {
        editor?.chain().focus().updateAttributes('paragraph', { lineHeight: value }).run();
    };

    // Kosong artinya belum di-override → tampilkan default situs: Poppins 14px.
    const currentFontSize =
        (toolbar.textStyle.fontSize as string | undefined) || '14px';
    const currentFontFamily =
        (toolbar.textStyle.fontFamily as string | undefined) || 'Poppins';
    const currentColor = (toolbar.textStyle.color as string | undefined) ?? '';

    const toolbarElement = (
        <div className="flex flex-wrap items-center gap-0.5 border-b bg-muted/40 px-2 py-1.5">
            <ToolbarButton
                label="Urungkan"
                shortcut="Ctrl+Z"
                disabled={!toolbar.canUndo}
                onClick={() => editor?.chain().focus().undo().run()}
            >
                <Undo2 className="size-4" />
            </ToolbarButton>
            <ToolbarButton
                label="Ulangi"
                shortcut="Ctrl+Shift+Z"
                disabled={!toolbar.canRedo}
                onClick={() => editor?.chain().focus().redo().run()}
            >
                <Redo2 className="size-4" />
            </ToolbarButton>

            <Divider />

            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Format teks"
                        aria-label="Format teks"
                        className={cn(
                            'flex size-8 items-center justify-center gap-0.5 rounded-md transition-colors',
                            toolbar.bold ||
                                toolbar.italic ||
                                toolbar.underline ||
                                toolbar.strike ||
                                toolbar.sub ||
                                toolbar.sup
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        {toolbar.bold ? (
                            <Bold className="size-4" />
                        ) : toolbar.italic ? (
                            <Italic className="size-4" />
                        ) : toolbar.underline ? (
                            <UnderlineIcon className="size-4" />
                        ) : toolbar.strike ? (
                            <Strikethrough className="size-4" />
                        ) : toolbar.sub ? (
                            <SubscriptIcon className="size-4" />
                        ) : toolbar.sup ? (
                            <SuperscriptIcon className="size-4" />
                        ) : (
                            <Type className="size-4" />
                        )}
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-44">
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleBold().run()
                        }
                    >
                        <Bold className="size-4" />
                        Tebal
                        <DropdownMenuShortcut>Ctrl+B</DropdownMenuShortcut>
                        {toolbar.bold && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleItalic().run()
                        }
                    >
                        <Italic className="size-4" />
                        Miring
                        <DropdownMenuShortcut>Ctrl+I</DropdownMenuShortcut>
                        {toolbar.italic && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleUnderline().run()
                        }
                    >
                        <UnderlineIcon className="size-4" />
                        Garis bawah
                        <DropdownMenuShortcut>Ctrl+U</DropdownMenuShortcut>
                        {toolbar.underline && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleStrike().run()
                        }
                    >
                        <Strikethrough className="size-4" />
                        Coret
                        <DropdownMenuShortcut>
                            Ctrl+Shift+S
                        </DropdownMenuShortcut>
                        {toolbar.strike && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleSubscript().run()
                        }
                    >
                        <SubscriptIcon className="size-4" />
                        Subskrip
                        {toolbar.sub && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleSuperscript().run()
                        }
                    >
                        <SuperscriptIcon className="size-4" />
                        Superskrip
                        {toolbar.sup && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>

            <Divider />

            {/* Heading — satu grup dropdown ringkas (paragraph / H1 / H2 / H3) */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Gaya heading"
                        aria-label="Gaya heading"
                        className={cn(
                            'flex size-8 items-center justify-center gap-0.5 rounded-md transition-colors',
                            toolbar.h1 || toolbar.h2 || toolbar.h3
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        {toolbar.h1 ? (
                            <Heading1 className="size-4" />
                        ) : toolbar.h2 ? (
                            <Heading2 className="size-4" />
                        ) : toolbar.h3 ? (
                            <Heading3 className="size-4" />
                        ) : (
                            <Pilcrow className="size-4" />
                        )}
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-44">
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().setParagraph().run()
                        }
                    >
                        <Pilcrow className="size-4" />
                        Paragraph
                        {toolbar.paragraph && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor
                                ?.chain()
                                .focus()
                                .toggleHeading({ level: 1 })
                                .run()
                        }
                    >
                        <Heading1 className="size-4" />
                        Judul utama (H1)
                        {toolbar.h1 && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor
                                ?.chain()
                                .focus()
                                .toggleHeading({ level: 2 })
                                .run()
                        }
                    >
                        <Heading2 className="size-4" />
                        Subjudul (H2)
                        {toolbar.h2 && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor
                                ?.chain()
                                .focus()
                                .toggleHeading({ level: 3 })
                                .run()
                        }
                    >
                        <Heading3 className="size-4" />
                        Sub-subjudul (H3)
                        {toolbar.h3 && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>

            <Divider />

            {/* Jenis & ukuran font */}
            <select
                aria-label="Jenis font"
                title="Jenis font"
                value={currentFontFamily}
                onChange={(event) => setFontFamily(event.target.value)}
                className="h-8 rounded-md border bg-background px-1.5 text-xs text-muted-foreground focus:ring-2 focus:ring-ring focus:outline-none"
            >
                <option value="">Font</option>
                {FONT_FAMILIES.map((font) => (
                    <option key={font.value} value={font.value}>
                        {font.label}
                    </option>
                ))}
            </select>
            <select
                aria-label="Ukuran font"
                title="Ukuran font"
                value={currentFontSize}
                onChange={(event) => setFontSize(event.target.value)}
                className="h-8 rounded-md border bg-background px-1.5 text-xs text-muted-foreground focus:ring-2 focus:ring-ring focus:outline-none"
            >
                <option value="">Ukuran</option>
                {FONT_SIZES.map((size) => (
                    <option key={size.value} value={size.value}>
                        {size.label}
                    </option>
                ))}
            </select>

            <Divider />

            {/* Warna teks */}
            <div className="relative flex size-8 items-center justify-center">
                <ToolbarButton
                    label="Warna teks"
                    active={Boolean(currentColor)}
                    onClick={() => {
                        const colorPicker = document.getElementById(
                            `color-picker-${pickerId}`,
                        ) as HTMLInputElement | null;
                        colorPicker?.click();
                    }}
                >
                    <Palette className="size-4" />
                </ToolbarButton>
                <input
                    id={`color-picker-${pickerId}`}
                    type="color"
                    value={currentColor || '#0f172a'}
                    onChange={(event) =>
                        editor
                            ?.chain()
                            .focus()
                            .setColor(event.target.value)
                            .run()
                    }
                    className="absolute inset-0 size-full cursor-pointer opacity-0"
                    aria-label="Pilih warna teks"
                />
            </div>

            {/* Highlight */}
            <div className="relative flex size-8 items-center justify-center">
                <ToolbarButton
                    label="Sorot (highlighter)"
                    active={toolbar.highlight}
                    onClick={() => {
                        const colorPicker = document.getElementById(
                            `highlight-picker-${pickerId}`,
                        ) as HTMLInputElement | null;
                        colorPicker?.click();
                    }}
                >
                    <Highlighter className="size-4" />
                </ToolbarButton>
                <input
                    id={`highlight-picker-${pickerId}`}
                    type="color"
                    value="#fef08a"
                    onChange={(event) =>
                        editor
                            ?.chain()
                            .focus()
                            .toggleHighlight({
                                color: event.target.value,
                            })
                            .run()
                    }
                    className="absolute inset-0 size-full cursor-pointer opacity-0"
                    aria-label="Pilih warna sorot"
                />
            </div>

            <Divider />

            {/* Daftar — satu grup dropdown ringkas (bullet / nomor / 1. / a. / A. / i. / I.) */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Gaya daftar"
                        aria-label="Gaya daftar"
                        className={cn(
                            'flex size-8 items-center justify-center gap-0.5 rounded-md transition-colors',
                            toolbar.bullet || toolbar.ordered
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        {toolbar.bullet ? (
                            <List className="size-4" />
                        ) : toolbar.ordered &&
                          toolbar.orderedListType !== '1' ? (
                            <span className="text-xs font-semibold">
                                {LIST_STYLES.find(
                                    (style) =>
                                        style.value === toolbar.orderedListType,
                                )?.short ?? '1.'}
                            </span>
                        ) : (
                            <List className="size-4" />
                        )}
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-44">
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleBulletList().run()
                        }
                    >
                        <List className="size-4" />
                        Bullet
                        {toolbar.bullet && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().toggleOrderedList().run()
                        }
                    >
                        <ListOrdered className="size-4" />
                        Nomor (1. 2. 3.)
                        {toolbar.ordered && toolbar.orderedListType === '1' && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    {LIST_STYLES.slice(1).map((style) => (
                        <DropdownMenuItem
                            key={style.value}
                            onClick={() => setOrderedListStyle(style.value)}
                        >
                            <span className="w-4 text-center text-xs font-semibold">
                                {style.short}
                            </span>
                            {style.title}
                            {toolbar.orderedListType === style.value && (
                                <Check className="ml-auto size-4 text-primary" />
                            )}
                        </DropdownMenuItem>
                    ))}
                </DropdownMenuContent>
            </DropdownMenu>
            <ToolbarButton
                label="Daftar tugas (task list)"
                active={toolbar.task}
                onClick={() => editor?.chain().focus().toggleTaskList().run()}
            >
                <ListChecks className="size-4" />
            </ToolbarButton>
            <ToolbarButton
                label="Kutipan"
                active={toolbar.quote}
                onClick={() => editor?.chain().focus().toggleBlockquote().run()}
            >
                <Quote className="size-4" />
            </ToolbarButton>
            <ToolbarButton
                label="Kode inline"
                active={toolbar.code}
                onClick={() => editor?.chain().focus().toggleCode().run()}
            >
                <Code2 className="size-4" />
            </ToolbarButton>
            <ToolbarButton
                label="Blok kode"
                active={toolbar.codeBlock}
                onClick={() => editor?.chain().focus().toggleCodeBlock().run()}
            >
                <SquareCode className="size-4" />
            </ToolbarButton>

            <Divider />

            {/* Tautan — satu grup dropdown ringkas (tambah / hapus) */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Tautan"
                        aria-label="Tautan"
                        className={cn(
                            'flex size-8 items-center justify-center gap-0.5 rounded-md transition-colors',
                            toolbar.link
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        <LinkIcon className="size-4" />
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-44">
                    <DropdownMenuItem onClick={setLink}>
                        <LinkIcon className="size-4" />
                        Tambah link
                        {toolbar.link && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        disabled={!toolbar.link}
                        onClick={() =>
                            editor?.chain().focus().unsetLink().run()
                        }
                    >
                        <Unlink className="size-4" />
                        Hapus link
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>

            <Divider />

            {/* Perataan — satu grup dropdown ringkas (kiri/tengah/kanan/justify) */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Perataan teks"
                        aria-label="Perataan teks"
                        className={cn(
                            'flex size-8 items-center justify-center gap-0.5 rounded-md transition-colors',
                            toolbar.alignCenter ||
                                toolbar.alignRight ||
                                toolbar.alignJustify
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        {toolbar.alignCenter ? (
                            <AlignCenter className="size-4" />
                        ) : toolbar.alignRight ? (
                            <AlignRight className="size-4" />
                        ) : toolbar.alignJustify ? (
                            <AlignJustify className="size-4" />
                        ) : (
                            <AlignLeft className="size-4" />
                        )}
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-44">
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().setTextAlign('left').run()
                        }
                    >
                        <AlignLeft className="size-4" />
                        Rata kiri
                        {toolbar.alignLeft && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().setTextAlign('center').run()
                        }
                    >
                        <AlignCenter className="size-4" />
                        Rata tengah
                        {toolbar.alignCenter && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor?.chain().focus().setTextAlign('right').run()
                        }
                    >
                        <AlignRight className="size-4" />
                        Rata kanan
                        {toolbar.alignRight && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        onClick={() =>
                            editor
                                ?.chain()
                                .focus()
                                .setTextAlign('justify')
                                .run()
                        }
                    >
                        <AlignJustify className="size-4" />
                        Rata kanan-kiri (justify)
                        {toolbar.alignJustify && (
                            <Check className="ml-auto size-4 text-primary" />
                        )}
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>

            <Divider />

            {/* Spasi baris (line-height) — dropdown ukuran ala MS Office */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Spasi baris"
                        aria-label="Spasi baris"
                        className={cn(
                            'flex h-8 items-center justify-center gap-1 rounded-md px-2 text-xs font-medium transition-colors',
                            toolbar.lineHeight
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        <ChevronsUpDown className="size-4" />
                        <span className="tabular-nums">{toolbar.lineHeight ?? '1.5'}</span>
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-40">
                    {LINE_HEIGHT_OPTIONS.map((v) => (
                        <DropdownMenuItem
                            key={v}
                            onClick={() => setLineHeight(v)}
                        >
                            <span className="tabular-nums">{v}</span>
                            {(toolbar.lineHeight ?? '1.5') === v && (
                                <Check className="ml-auto size-4 text-primary" />
                            )}
                        </DropdownMenuItem>
                    ))}
                </DropdownMenuContent>
            </DropdownMenu>

            <Divider />

            {/* Tabel — satu grup dropdown ringkas (sisipkan / baris / kolom) */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Tabel"
                        aria-label="Tabel"
                        className={cn(
                            'flex size-8 items-center justify-center gap-0.5 rounded-md transition-colors',
                            toolbar.table
                                ? 'bg-primary/10 text-primary'
                                : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                        )}
                    >
                        <Table2 className="size-4" />
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-48">
                    <DropdownMenuItem onClick={insertTable}>
                        <Table2 className="size-4" />
                        Sisipkan tabel
                    </DropdownMenuItem>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem
                        disabled={!toolbar.table}
                        onClick={() =>
                            editor?.chain().focus().addRowAfter().run()
                        }
                    >
                        <ArrowDownToLine className="size-4" />
                        Tambah baris di bawah
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        disabled={!toolbar.table}
                        onClick={() =>
                            editor?.chain().focus().deleteRow().run()
                        }
                    >
                        <ArrowUpFromLine className="size-4" />
                        Hapus baris
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        disabled={!toolbar.table}
                        onClick={() =>
                            editor?.chain().focus().addColumnAfter().run()
                        }
                    >
                        <ArrowRightToLine className="size-4" />
                        Tambah kolom di kanan
                    </DropdownMenuItem>
                    <DropdownMenuItem
                        disabled={!toolbar.table}
                        onClick={() =>
                            editor?.chain().focus().deleteColumn().run()
                        }
                    >
                        <ArrowLeftFromLine className="size-4" />
                        Hapus kolom
                    </DropdownMenuItem>
                    <DropdownMenuSeparator />
                    <DropdownMenuItem
                        disabled={!toolbar.table}
                        onClick={deleteTable}
                        variant="destructive"
                    >
                        <Trash2 className="size-4" />
                        Hapus tabel
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>

            <Divider />

            {/* Media — upload baru atau pilih dari Library Media */}
            <DropdownMenu>
                <DropdownMenuTrigger asChild>
                    <button
                        type="button"
                        title="Sisipkan gambar"
                        aria-label="Sisipkan gambar"
                        className="flex size-8 items-center justify-center gap-0.5 rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
                    >
                        {uploading ? (
                            <Loader2 className="size-4 animate-spin" />
                        ) : (
                            <ImagePlus className="size-4" />
                        )}
                        <ChevronDown className="size-3" />
                    </button>
                </DropdownMenuTrigger>
                <DropdownMenuContent align="start" className="min-w-44">
                    <DropdownMenuItem
                        disabled={uploading}
                        onClick={() => fileInputRef.current?.click()}
                    >
                        <ImagePlus className="size-4" />
                        Unggah gambar
                    </DropdownMenuItem>
                    <DropdownMenuItem onClick={() => setPickerOpen(true)}>
                        <Images className="size-4" />
                        Pilih dari Library
                    </DropdownMenuItem>
                </DropdownMenuContent>
            </DropdownMenu>
            <ToolbarButton
                label="Garis pemisah (HR)"
                onClick={() =>
                    editor?.chain().focus().setHorizontalRule().run()
                }
            >
                <Minus className="size-4" />
            </ToolbarButton>

            <Divider />

            {/* Bersihkan format */}
            <ToolbarButton label="Hapus format" onClick={clearFormatting}>
                <Eraser className="size-4" />
            </ToolbarButton>
        </div>
    );

    return (
        <div className="rich-text-editor relative space-y-1.5">
            {label && <span className="text-sm font-medium">{label}</span>}

            <div className="flex flex-col rounded-lg border bg-background">
                {/* Toolbar — fixed at top, never scrolls */}
                <div className="shrink-0">{toolbarElement}</div>

                {/* Floating toolbar untuk gambar yang dipilih — align & resize */}
                {imageToolbarPos && (
                    <div
                        ref={imageToolbarRef}
                        className="absolute z-50 flex items-center gap-0.5 rounded-lg border bg-background p-1 shadow-lg animate-in fade-in zoom-in-95"
                        style={{ top: imageToolbarPos.top, left: Math.max(0, imageToolbarPos.left) }}
                    >
                        <button
                            type="button"
                            title="Rata kiri"
                            onClick={() => updateSelectedImage({ dataAlign: selectedImageAlign === 'left' ? null : 'left' })}
                            className={cn(
                                'flex size-7 items-center justify-center rounded-md transition-colors',
                                selectedImageAlign === 'left' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                            )}
                        >
                            <AlignLeft className="size-3.5" />
                        </button>
                        <button
                            type="button"
                            title="Rata tengah"
                            onClick={() => updateSelectedImage({ dataAlign: selectedImageAlign === 'center' ? null : 'center' })}
                            className={cn(
                                'flex size-7 items-center justify-center rounded-md transition-colors',
                                selectedImageAlign === 'center' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                            )}
                        >
                            <AlignCenter className="size-3.5" />
                        </button>
                        <button
                            type="button"
                            title="Rata kanan"
                            onClick={() => updateSelectedImage({ dataAlign: selectedImageAlign === 'right' ? null : 'right' })}
                            className={cn(
                                'flex size-7 items-center justify-center rounded-md transition-colors',
                                selectedImageAlign === 'right' ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                            )}
                        >
                            <AlignRight className="size-3.5" />
                        </button>

                        <div className="mx-0.5 h-4 w-px bg-border" />

                        {IMAGE_SIZES.map((size) => (
                            <button
                                key={size.value}
                                type="button"
                                title={`${size.label} lebar`}
                                onClick={() => updateSelectedImage({ dataWidth: selectedImageWidth === size.value ? null : size.value })}
                                className={cn(
                                    'flex h-7 min-w-7 items-center justify-center rounded-md px-1 text-[10px] font-medium transition-colors',
                                    selectedImageWidth === size.value ? 'bg-primary text-primary-foreground' : 'text-muted-foreground hover:bg-muted hover:text-foreground',
                                )}
                            >
                                {size.label}
                            </button>
                        ))}

                        <div className="mx-0.5 h-4 w-px bg-border" />

                        <button
                            type="button"
                            title="Hapus gambar"
                            onClick={() => {
                                if (!editor) {
return;
}

                                const { from } = editor.state.selection;
                                editor.chain().focus().setNodeSelection(from).deleteSelection().run();
                                setImageToolbarPos(null);
                            }}
                            className="flex size-7 items-center justify-center rounded-md text-destructive transition-colors hover:bg-destructive/10"
                        >
                            <Trash2 className="size-3.5" />
                        </button>
                    </div>
                )}

                <div
                    className="tiptap-scroll-container relative overflow-y-auto"
                    style={{ height: editorHeight }}
                >
                    <EditorContent editor={editor} className="h-full" />
                </div>

                {/* Drag handle — resize editor height */}
                <div
                    onMouseDown={onResizeMouseDown}
                    className="flex h-5 shrink-0 cursor-ns-resize items-center justify-center border-t bg-muted/30 transition-colors hover:bg-muted/60"
                    title="Geser untuk mengubah tinggi editor"
                >
                    <GripVertical className="size-3.5 text-muted-foreground" />
                </div>

                <input
                    ref={fileInputRef}
                    type="file"
                    accept="image/jpeg,image/png,image/webp"
                    className="hidden"
                    onChange={handleImageFile}
                />
            </div>

            {pickerOpen && (
                <MediaPickerDialog
                    open
                    multiple
                    onOpenChange={setPickerOpen}
                    onSelect={handlePickFromLibrary}
                />
            )}
        </div>
    );
}
