"use client";

import { NodeViewContent, NodeViewWrapper, NodeViewProps } from "@tiptap/react";
import React, { useMemo } from "react";
import { Copy, Check, Trash2, ArrowUpToLine, ArrowDownToLine } from "lucide-react";
import { LanguageSelector } from "./language-selector";

export function CodeBlockComponent({
    node,
    updateAttributes,
    extension,
    deleteNode,
    editor,
    getPos,
}: NodeViewProps) {
    const codeBg = "hsl(var(--code-bg))";
    const { language: defaultLanguage } = node.attrs;
    const { textContent } = node;
    const [copied, setCopied] = React.useState(false);

    const languages = extension.options.lowlight ? extension.options.lowlight.listLanguages() : [];

    const popularLanguages = ["html", "javascript", "typescript", "css", "json", "python", "java", "go", "bash", "sql"];
    const otherLanguages = languages.filter((lang: string) => !popularLanguages.includes(lang) && lang !== "xml");
    const displayLanguages = Array.from(new Set([...popularLanguages, ...otherLanguages]));

    const insertAbove = () => {
        if (typeof getPos === "function") {
            const pos = getPos();
            if (typeof pos !== "number") return;
            editor.chain().insertContentAt(pos, { type: "paragraph" }).focus().setTextSelection(pos + 1).scrollIntoView().run();
        }
    };

    const insertBelow = () => {
        if (typeof getPos === "function") {
            const pos = getPos();
            if (typeof pos !== "number") return;
            const targetPos = pos + node.nodeSize;
            editor.chain().insertContentAt(targetPos, { type: "paragraph" }).focus().setTextSelection(targetPos + 1).scrollIntoView().run();
        }
    };

    const handleCopy = () => {
        navigator.clipboard.writeText(textContent);
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
    };

    const lineNumbers = useMemo(() => {
        const lines = textContent.split("\n").length;
        return Array.from({ length: lines }, (_, i) => i + 1);
    }, [textContent]);

    return (
        <NodeViewWrapper className="group code-block relative my-4 overflow-hidden rounded-lg border border-border/40 shadow-sm" style={{ backgroundColor: codeBg }}>
            <div
                className="flex select-none items-center justify-between border-b border-border/50 px-3 py-2 text-xs text-zinc-400"
                style={{ backgroundColor: "hsl(var(--code-bg) / 0.9)" }}
            >
                <div className="flex items-center gap-2">
                    <LanguageSelector
                        language={defaultLanguage || "null"}
                        onChange={(val) => {
                            updateAttributes({ language: val });
                        }}
                        languages={displayLanguages}
                    />
                </div>

                <div className="flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100">
                    <button onClick={insertAbove} className="rounded p-1.5 transition-all hover:bg-white/10 hover:text-white" title="在上方插入">
                        <ArrowUpToLine size={14} />
                    </button>
                    <button onClick={insertBelow} className="rounded p-1.5 transition-all hover:bg-white/10 hover:text-white" title="在下方插入">
                        <ArrowDownToLine size={14} />
                    </button>
                    <div className="mx-1 h-3 w-px bg-white/10" />
                    <button onClick={handleCopy} className="rounded p-1.5 transition-all hover:bg-white/10 hover:text-white" title="复制代码">
                        {copied ? <Check size={14} className="text-green-500" /> : <Copy size={14} />}
                    </button>
                    <button onClick={() => deleteNode()} className="rounded p-1.5 transition-all hover:bg-white/10 hover:text-red-400" title="删除代码块">
                        <Trash2 size={14} />
                    </button>
                </div>
            </div>

            <div className="relative grid grid-cols-[auto_1fr] font-mono text-sm leading-6" style={{ backgroundColor: codeBg }}>
                <div className="select-none border-r border-white/5 px-2 py-4 text-right text-zinc-500" style={{ minWidth: "2.5rem" }} contentEditable={false}>
                    {lineNumbers.map((line) => (
                        <div key={line} className="px-1">
                            {line}
                        </div>
                    ))}
                </div>

                <pre className="scrollbar-thin scrollbar-track-transparent scrollbar-thumb-white/10 !my-0 !border-0 !p-0 overflow-x-auto text-zinc-300" style={{ backgroundColor: codeBg }}>
                    <NodeViewContent
                        as={"code" as unknown as "div"}
                        className="block min-w-full !whitespace-pre !bg-transparent !p-4 !font-mono !text-sm !leading-6 outline-none"
                    />
                </pre>
            </div>
        </NodeViewWrapper>
    );
}
