"use client";

import { Toaster } from "@mdxui/primitives/sonner";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import { toast } from "sonner";
import { useAutosave } from "../hooks/use-autosave";
import type { EditorPanelProps } from "./types";
import {
	type EditorContextValue,
	type EditorHandle,
	EditorProvider,
} from "./editor-context";
import { EditorDrawer } from "./editor-drawer";
import { EditorTrigger } from "./editor-trigger";

export function EditorPanel({
	path = "",
	initialContent = "",
	onSave,
	shortcut = "meta+i",
	showTrigger = true,
}: EditorPanelProps) {
	const [isOpen, setIsOpen] = useState(false);
	const [content, setContent] = useState(initialContent);
	const [savedContent, setSavedContent] = useState(initialContent);
	const [isSaving, setIsSaving] = useState(false);

	// Ref for editor handle (jump-to-line, etc.)
	const editorRef = useRef<EditorHandle | null>(null);

	const isDirty = content !== savedContent;

	// Autosave hook
	const {
		showRecoveryPrompt,
		recoveredData,
		clearAutosave,
		handleRestore,
		handleDiscardRecovery,
	} = useAutosave(path, content, isDirty, initialContent);

	// Handle recovery restoration
	const onRestoreRecovery = useCallback(() => {
		const restored = handleRestore();
		if (restored) {
			setContent(restored);
			toast.success("Changes restored");
		}
	}, [handleRestore]);

	// Handle recovery dismissal
	const onDismissRecovery = useCallback(() => {
		handleDiscardRecovery();
		toast("Recovered changes discarded");
	}, [handleDiscardRecovery]);

	// Toggle shortcut
	useHotkeys(
		shortcut,
		() => setIsOpen((prev) => !prev),
		{
			enableOnFormTags: false,
			preventDefault: true,
		},
		[shortcut],
	);

	// Save shortcut (when open)
	useHotkeys(
		"meta+s",
		async (e) => {
			if (!isOpen || !isDirty) return;
			e.preventDefault();
			await handleSave();
		},
		{
			enableOnFormTags: true,
			enabled: isOpen,
		},
		[isOpen, isDirty, content],
	);

	// Save handler
	const handleSave = useCallback(async () => {
		if (!onSave || !isDirty) return;

		setIsSaving(true);
		try {
			await onSave(content);
			setSavedContent(content);
			clearAutosave();
			toast.success("Saved successfully");
		} catch (error) {
			toast.error("Failed to save", {
				description: "Check your connection and try again.",
				action: {
					label: "Retry",
					onClick: () => handleSave(),
				},
			});
			console.error("Save error:", error);
		} finally {
			setIsSaving(false);
		}
	}, [content, isDirty, onSave, clearAutosave]);

	// Close handler - just close, autosave protects user's work
	const handleClose = useCallback(() => {
		if (isDirty) {
			// Reset to saved content and notify user
			setContent(savedContent);
			toast("Changes discarded", {
				description: "Your work was auto-saved and can be restored next time.",
			});
		}
		setIsOpen(false);
	}, [isDirty, savedContent]);

	// Sync content when initialContent changes (e.g., after external save)
	useEffect(() => {
		if (!isDirty) {
			setContent(initialContent);
			setSavedContent(initialContent);
		}
	}, [initialContent, isDirty]);

	// Memoize context value to prevent unnecessary re-renders
	const editorContextValue = useMemo<EditorContextValue>(
		() => ({
			content,
			onChange: setContent,
			path,
			isDirty,
			isSaving,
			onSave: handleSave,
			onClose: handleClose,
			editorRef,
			// Recovery banner state (only show if we have recovered data)
			recovery:
				showRecoveryPrompt && recoveredData
					? {
							timestamp: recoveredData.timestamp,
							onRestore: onRestoreRecovery,
							onDismiss: onDismissRecovery,
						}
					: undefined,
		}),
		[
			content,
			path,
			isDirty,
			isSaving,
			handleSave,
			handleClose,
			showRecoveryPrompt,
			recoveredData,
			onRestoreRecovery,
			onDismissRecovery,
		],
	);

	return (
		<>
			{/* Toast container */}
			<Toaster position="bottom-right" />

			{/* Trigger button */}
			{showTrigger && (
				<EditorTrigger
					isOpen={isOpen}
					onToggle={() => (isOpen ? handleClose() : setIsOpen(true))}
				/>
			)}

			{/* Editor drawer with context provider */}
			<EditorProvider value={editorContextValue}>
				<EditorDrawer isOpen={isOpen} />
			</EditorProvider>
		</>
	);
}
