import { useRef, useCallback, useState, useEffect } from 'react';
import { useEditor, useEditorState, EditorContent, type Editor } from '@tiptap/react';
import { Node, mergeAttributes } from '@tiptap/core';
import StarterKit from '@tiptap/starter-kit';
import Placeholder from '@tiptap/extension-placeholder';
import TiptapImage from '@tiptap/extension-image';
import Youtube from '@tiptap/extension-youtube';
import {
    Bold,
    Italic,
    Strikethrough,
    Code,
    List,
    ListOrdered,
    Quote,
    Minus,
    Link as LinkIcon,
    Undo,
    Redo,
    Image as ImageIcon,
    Video,
    FileText,
    Maximize2,
    Minimize2,
    ChevronDown,
} from 'lucide-react';

declare module '@tiptap/core' {
    interface Commands<ReturnType> {
        iframe: {
            setIframe: (attrs: { src: string; title?: string }) => ReturnType;
        };
    }
}

const IframeNode = Node.create({
    name: 'iframe',
    group: 'block',
    atom: true,

    addAttributes() {
        return {
            src: { default: null },
            title: { default: '' },
        };
    },

    parseHTML() {
        return [
            {
                tag: 'div[data-type="iframe"]',
                getAttrs: (el) => ({
                    src: (el as HTMLElement).getAttribute('data-src'),
                    title: (el as HTMLElement).getAttribute('data-title') ?? '',
                }),
            },
        ];
    },

    renderHTML({ HTMLAttributes }) {
        return [
            'div',
            {
                'data-type': 'iframe',
                'data-src': HTMLAttributes.src,
                'data-title': HTMLAttributes.title,
                class: 'not-prose my-4 overflow-hidden rounded-lg border',
            },
            [
                'iframe',
                mergeAttributes(
                    { src: HTMLAttributes.src, title: HTMLAttributes.title },
                    { class: 'w-full', style: 'height:480px', allowfullscreen: 'true', loading: 'lazy' },
                ),
            ],
        ];
    },

    addNodeView() {
        return ({ node }) => {
            const wrapper = document.createElement('div');
            wrapper.setAttribute('data-type', 'iframe');
            wrapper.className = 'not-prose my-4 overflow-hidden rounded-lg border';
            wrapper.contentEditable = 'false';

            const iframe = document.createElement('iframe');
            iframe.src = node.attrs.src ?? '';
            iframe.title = node.attrs.title ?? '';
            iframe.className = 'w-full';
            iframe.style.height = '480px';
            iframe.allowFullscreen = true;
            wrapper.appendChild(iframe);

            return { dom: wrapper };
        };
    },

    addCommands() {
        return {
            setIframe:
                (attrs) =>
                ({ chain }) =>
                    chain()
                        .insertContent({ type: this.name, attrs })
                        .run(),
        };
    },
});

function ToolbarBtn({
    onClick,
    active,
    disabled,
    title,
    children,
}: {
    onClick: () => void;
    active?: boolean;
    disabled?: boolean;
    title: string;
    children: React.ReactNode;
}) {
    return (
        <button
            type="button"
            onMouseDown={(e) => {
                e.preventDefault();
                onClick();
            }}
            disabled={disabled}
            title={title}
            className={`rounded p-1.5 transition-colors ${
                active
                    ? 'bg-primary text-primary-foreground'
                    : 'text-muted-foreground hover:bg-muted hover:text-foreground'
            } disabled:opacity-30`}
        >
            {children}
        </button>
    );
}

type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;

function HeadingDropdown({ editor }: { editor: Editor }) {
    const [open, setOpen] = useState(false);

    const { activeLevel } = useEditorState({
        editor,
        selector: (ctx) => ({
            activeLevel: ctx.editor.isActive('heading')
                ? (ctx.editor.getAttributes('heading').level as HeadingLevel)
                : undefined,
        }),
    });
    const label = activeLevel ? `H${activeLevel}` : 'Normal';

    function select(level: HeadingLevel | null) {
        setOpen(false);
        if (level === null) {
            editor.chain().focus().setParagraph().run();
        } else {
            editor.chain().focus().toggleHeading({ level }).run();
        }
    }

    return (
        <div className="relative">
            <button
                type="button"
                onMouseDown={(e) => {
                    e.preventDefault();
                    setOpen((v) => !v);
                }}
                title="Heading"
                className="flex items-center gap-0.5 rounded px-2 py-1.5 text-xs font-medium transition-colors text-muted-foreground hover:bg-muted hover:text-foreground"
            >
                <span className="min-w-[3ch]">{label}</span>
                <ChevronDown className="h-3 w-3" />
            </button>

            {open && (
                <>
                    <div className="fixed inset-0 z-40" onMouseDown={() => setOpen(false)} />
                    <div className="absolute left-0 top-full z-50 mt-1 w-28 overflow-hidden rounded-md border bg-popover shadow-md">
                        <button
                            type="button"
                            onMouseDown={(e) => { e.preventDefault(); select(null); }}
                            className="w-full px-3 py-1.5 text-left text-sm hover:bg-muted"
                        >
                            Normal
                        </button>
                        {([1, 2, 3, 4, 5, 6] as HeadingLevel[]).map((l) => (
                            <button
                                key={l}
                                type="button"
                                onMouseDown={(e) => { e.preventDefault(); select(l); }}
                                className={`w-full px-3 py-1.5 text-left text-sm hover:bg-muted ${
                                    editor.isActive('heading', { level: l }) ? 'bg-primary/10 font-semibold text-primary' : ''
                                }`}
                                style={{ fontSize: `${1 - (l - 1) * 0.07}rem` }}
                            >
                                H{l} — Heading {l}
                            </button>
                        ))}
                    </div>
                </>
            )}
        </div>
    );
}

function Toolbar({
    editor,
    onImagePick,
    fullscreen,
    onToggleFullscreen,
}: {
    editor: Editor;
    onImagePick: () => void;
    fullscreen: boolean;
    onToggleFullscreen: () => void;
}) {
    function setLink() {
        const prev = editor.getAttributes('link').href as string | undefined;
        const url = window.prompt('URL:', prev ?? 'https://');
        if (url === null) return;
        if (url === '') {
            editor.chain().focus().extendMarkRange('link').unsetLink().run();
            return;
        }
        editor.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
    }

    function insertVideo() {
        const url = window.prompt('URL YouTube / Vimeo:');
        if (!url) return;
        editor.commands.setYoutubeVideo({ src: url });
    }

    function insertPdf() {
        const url = window.prompt('URL File PDF:');
        if (!url) return;
        editor.commands.setIframe({ src: url, title: 'PDF' });
    }

    return (
        <div className="flex flex-wrap items-center gap-0.5 border-b bg-muted/30 px-2 py-1.5">
            {/* Heading dropdown */}
            <HeadingDropdown editor={editor} />

            <span className="mx-1 h-5 w-px bg-border" />

            {/* Teks */}
            <ToolbarBtn title="Bold" onClick={() => editor.chain().focus().toggleBold().run()} active={editor.isActive('bold')}>
                <Bold className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Italic" onClick={() => editor.chain().focus().toggleItalic().run()} active={editor.isActive('italic')}>
                <Italic className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Strikethrough" onClick={() => editor.chain().focus().toggleStrike().run()} active={editor.isActive('strike')}>
                <Strikethrough className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Inline code" onClick={() => editor.chain().focus().toggleCode().run()} active={editor.isActive('code')}>
                <Code className="h-4 w-4" />
            </ToolbarBtn>

            <span className="mx-1 h-5 w-px bg-border" />

            {/* List & blok */}
            <ToolbarBtn title="Bullet list" onClick={() => editor.chain().focus().toggleBulletList().run()} active={editor.isActive('bulletList')}>
                <List className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn
                title="Numbered list"
                onClick={() => editor.chain().focus().toggleOrderedList().run()}
                active={editor.isActive('orderedList')}
            >
                <ListOrdered className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Blockquote" onClick={() => editor.chain().focus().toggleBlockquote().run()} active={editor.isActive('blockquote')}>
                <Quote className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Code block" onClick={() => editor.chain().focus().toggleCodeBlock().run()} active={editor.isActive('codeBlock')}>
                <Code className="h-4 w-4 opacity-60" />
            </ToolbarBtn>
            <ToolbarBtn title="Divider" onClick={() => editor.chain().focus().setHorizontalRule().run()}>
                <Minus className="h-4 w-4" />
            </ToolbarBtn>

            <span className="mx-1 h-5 w-px bg-border" />

            {/* Link */}
            <ToolbarBtn title="Link" onClick={setLink} active={editor.isActive('link')}>
                <LinkIcon className="h-4 w-4" />
            </ToolbarBtn>

            <span className="mx-1 h-5 w-px bg-border" />

            {/* Media */}
            <ToolbarBtn title="Sisipkan Gambar (upload)" onClick={onImagePick}>
                <ImageIcon className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Sisipkan Video YouTube / Vimeo" onClick={insertVideo}>
                <Video className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Sisipkan PDF" onClick={insertPdf}>
                <FileText className="h-4 w-4" />
            </ToolbarBtn>

            <span className="mx-1 h-5 w-px bg-border" />

            {/* History */}
            <ToolbarBtn title="Undo" onClick={() => editor.chain().focus().undo().run()} disabled={!editor.can().undo()}>
                <Undo className="h-4 w-4" />
            </ToolbarBtn>
            <ToolbarBtn title="Redo" onClick={() => editor.chain().focus().redo().run()} disabled={!editor.can().redo()}>
                <Redo className="h-4 w-4" />
            </ToolbarBtn>

            {/* Fullscreen — pushed to the right */}
            <span className="flex-1" />
            <ToolbarBtn title={fullscreen ? 'Keluar Fullscreen' : 'Fullscreen'} onClick={onToggleFullscreen}>
                {fullscreen ? <Minimize2 className="h-4 w-4" /> : <Maximize2 className="h-4 w-4" />}
            </ToolbarBtn>
        </div>
    );
}

export default function RichEditor({
    value,
    onChange,
    placeholder = 'Tulis konten di sini...',
    minHeight = 320,
}: {
    value: string;
    onChange: (html: string) => void;
    placeholder?: string;
    minHeight?: number;
}) {
    const imageInputRef = useRef<HTMLInputElement>(null);
    const [fullscreen, setFullscreen] = useState(false);

    const editor = useEditor({
        extensions: [
            StarterKit.configure({
                link: { openOnClick: false, HTMLAttributes: { class: 'underline text-primary' } },
            }),
            Placeholder.configure({ placeholder }),
            TiptapImage.configure({
                inline: false,
                HTMLAttributes: { class: 'rounded-lg max-w-full' },
            }),
            Youtube.configure({
                nocookie: true,
            }),
            IframeNode,
        ],
        content: value,
        editorProps: {
            attributes: {
                class: 'prose prose-sm dark:prose-invert max-w-none focus:outline-none px-4 py-3',
                style: `min-height: ${minHeight}px`,
            },
        },
        onUpdate({ editor }) {
            onChange(editor.getHTML());
        },
    });

    useEffect(() => {
        if (editor && value !== editor.getHTML()) {
            editor.commands.setContent(value);
        }
    }, [value, editor]);

    const handleImageFile = useCallback(
        async (file: File) => {
            if (!editor) return;

            const formData = new FormData();
            formData.append('image', file);

            const match = document.cookie.match(/XSRF-TOKEN=([^;]+)/);
            const csrf = match ? decodeURIComponent(match[1]) : '';

            try {
                const res = await fetch('/instructor/media/image', {
                    method: 'POST',
                    headers: { 'X-XSRF-TOKEN': csrf },
                    body: formData,
                });

                if (!res.ok) throw new Error();

                const { url } = (await res.json()) as { url: string };
                editor.chain().focus().setImage({ src: url }).run();
            } catch {
                alert('Gagal mengupload gambar. Coba lagi.');
            }
        },
        [editor],
    );

    const triggerImagePicker = useCallback(() => {
        imageInputRef.current?.click();
    }, []);

    if (!editor) return null;

    const wrapperCls = fullscreen
        ? 'fixed inset-0 z-50 flex flex-col overflow-hidden rounded-none border-0 bg-background shadow-2xl'
        : 'overflow-hidden rounded-lg border bg-background shadow-xs transition-[box-shadow,border-color] focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/50';

    return (
        <div className={wrapperCls}>
            <input
                ref={imageInputRef}
                type="file"
                accept="image/*"
                className="hidden"
                onChange={(e) => {
                    const file = e.target.files?.[0];
                    if (file) void handleImageFile(file);
                    e.target.value = '';
                }}
            />
            <Toolbar editor={editor} onImagePick={triggerImagePicker} fullscreen={fullscreen} onToggleFullscreen={() => setFullscreen((v) => !v)} />
            <div className={fullscreen ? 'flex-1 overflow-y-auto bg-muted/40 py-10' : undefined}>
                <EditorContent
                    editor={editor}
                    className={
                        fullscreen
                            ? 'mx-auto w-full max-w-[794px] rounded-sm bg-background px-16 py-12 shadow-md [&_.tiptap]:!min-h-[calc(100vh-120px)]'
                            : undefined
                    }
                />
            </div>
        </div>
    );
}
