"use client";

import { Button } from "@mdxui/primitives/button";
import { Card } from "@mdxui/primitives/card";
import { cn } from "@mdxui/primitives/lib/utils";
import { AlertCircle, Edit3, Eye, Split } from "lucide-react";
import type React from "react";
import { useCallback, useEffect, useState } from "react";
import { createHighlighter, type Highlighter } from "shiki";

export interface MDXEditorProps {
	/** Initial MDX content */
	initialValue?: string;
	/** Callback when content changes */
	onChange?: (value: string) => void;
	/** Placeholder text */
	placeholder?: string;
	/** Default view mode */
	defaultMode?: "edit" | "preview" | "split";
	/** Height of the editor */
	height?: string | number;
	/** Additional CSS class */
	className?: string;
	/** Whether the editor is read-only */
	readOnly?: boolean;
	/** Custom preview renderer */
	renderPreview?: (mdx: string) => Promise<React.ReactNode> | React.ReactNode;
	/** Available components for MDX */
	components?: Record<string, React.ComponentType<any>>;
	/** Show syntax errors */
	showErrors?: boolean;
}

export const MDXEditor: React.FC<MDXEditorProps> = ({
	initialValue = "",
	onChange,
	placeholder = "# Start writing MDX\n\nImport and use React components...",
	defaultMode = "split",
	height = 500,
	className,
	readOnly = false,
	renderPreview,
	components: _components = {},
	showErrors = true,
}) => {
	const [content, setContent] = useState(initialValue);
	const [mode, setMode] = useState<"edit" | "preview" | "split">(defaultMode);
	const [highlighter, setHighlighter] = useState<Highlighter | null>(null);
	const [previewContent, setPreviewContent] = useState<React.ReactNode>(null);
	const [error, setError] = useState<string | null>(null);

	useEffect(() => {
		createHighlighter({
			themes: ["github-dark"],
			langs: ["mdx", "jsx", "tsx"],
		}).then(setHighlighter);
	}, []);

	const handleChange = useCallback(
		(value: string) => {
			setContent(value);
			onChange?.(value);
			setError(null);
		},
		[onChange],
	);

	useEffect(() => {
		if (mode === "preview" || mode === "split") {
			if (renderPreview) {
				Promise.resolve(renderPreview(content))
					.then((result) => {
						setPreviewContent(result);
						setError(null);
					})
					.catch((err) => {
						setError(err.message || "Failed to render MDX");
						setPreviewContent(null);
					});
			} else {
				// Default preview using syntax highlighting
				setPreviewContent(
					<div className="font-mono text-sm">
						<pre className="whitespace-pre-wrap">{content || placeholder}</pre>
					</div>,
				);
			}
		}
	}, [content, mode, renderPreview, placeholder]);

	const highlightedCode = highlighter
		? highlighter.codeToHtml(content || placeholder, {
				lang: "mdx",
				theme: "github-dark",
			})
		: "";

	const toolbar = (
		<div className="flex items-center justify-between border-b border-border p-2">
			<div className="flex items-center gap-1">
				<Button
					variant="ghost"
					size="sm"
					onClick={() => handleChange(content + "\n## New Section\n")}
					disabled={readOnly}
				>
					Add Section
				</Button>
				<Button
					variant="ghost"
					size="sm"
					onClick={() =>
						handleChange(content + "\n```tsx\n// Your code here\n```\n")
					}
					disabled={readOnly}
				>
					Code Block
				</Button>
				<Button
					variant="ghost"
					size="sm"
					onClick={() => handleChange(content + "\n<YourComponent />\n")}
					disabled={readOnly}
				>
					Component
				</Button>
			</div>
			<div className="flex items-center gap-1">
				<Button
					variant={mode === "edit" ? "default" : "ghost"}
					size="sm"
					onClick={() => setMode("edit")}
				>
					<Edit3 className="h-4 w-4" />
				</Button>
				<Button
					variant={mode === "split" ? "default" : "ghost"}
					size="sm"
					onClick={() => setMode("split")}
				>
					<Split className="h-4 w-4" />
				</Button>
				<Button
					variant={mode === "preview" ? "default" : "ghost"}
					size="sm"
					onClick={() => setMode("preview")}
				>
					<Eye className="h-4 w-4" />
				</Button>
			</div>
		</div>
	);

	const editorArea = (
		<div className="relative h-full">
			<textarea
				className={cn(
					"absolute inset-0 z-10 w-full resize-none p-4 font-mono text-sm caret-foreground outline-none",
					"bg-transparent text-transparent selection:bg-primary/20",
					readOnly && "cursor-not-allowed",
				)}
				value={content}
				onChange={(e) => handleChange(e.target.value)}
				placeholder={placeholder}
				readOnly={readOnly}
				spellCheck={false}
			/>
			<div
				className="pointer-events-none h-full overflow-auto"
				// biome-ignore lint/security/noDangerouslySetInnerHtml: we need to set the inner HTML for the code highlighting
				dangerouslySetInnerHTML={{ __html: highlightedCode }}
			/>
		</div>
	);

	const previewArea = (
		<div className="h-full overflow-auto p-4">
			{showErrors && error ? (
				<div className="flex items-start gap-2 rounded-md border border-destructive/50 bg-destructive/10 p-4 text-sm text-destructive">
					<AlertCircle className="mt-0.5 h-4 w-4 flex-shrink-0" />
					<div>
						<div className="font-medium">MDX Error</div>
						<div className="mt-1 text-xs opacity-90">{error}</div>
					</div>
				</div>
			) : (
				<div className="prose prose-sm max-w-none dark:prose-invert">
					{previewContent}
				</div>
			)}
		</div>
	);

	const containerHeight = typeof height === "number" ? `${height}px` : height;

	return (
		<Card className={cn("overflow-hidden", className)}>
			{toolbar}
			<div style={{ height: containerHeight }}>
				{mode === "split" ? (
					<div className="grid h-full grid-cols-2 divide-x divide-border">
						{editorArea}
						{previewArea}
					</div>
				) : mode === "edit" ? (
					editorArea
				) : (
					previewArea
				)}
			</div>
		</Card>
	);
};
