"use client";

/**
 * Code Snippet Field
 *
 * Displays code with Shiki syntax highlighting and copy functionality.
 * Supports light/dark themes automatically.
 */

import { Check, Copy } from "lucide-react";
import { useTheme } from "next-themes";
import { useCallback, useEffect, useState } from "react";
import { codeToHtml } from "shiki";
import {
	ANIMATION_CLASSES,
	getStaggerStyle,
	STAGGER_PRESETS,
} from "../animations";
import { cx } from "../lib/utils";
import type { CodeSnippetFieldProps } from "../types/fields";

export function CodeSnippetField({
	title,
	description,
	code,
	language = "typescript",
	showLineNumbers = false,
	showCopyButton = true,
	copyButtonText = "Copy",
	copiedText = "Copied!",
	animationIndex = 0,
}: CodeSnippetFieldProps) {
	const { resolvedTheme } = useTheme();
	const [highlightedCode, setHighlightedCode] = useState<string>("");
	const [copied, setCopied] = useState(false);
	const [mounted, setMounted] = useState(false);

	// Handle mounting to avoid hydration mismatch
	useEffect(() => {
		setMounted(true);
	}, []);

	// Highlight code when code, language, or theme changes
	useEffect(() => {
		if (!mounted) return;

		const highlight = async () => {
			try {
				const html = await codeToHtml(code, {
					lang: language,
					theme: resolvedTheme === "dark" ? "github-dark" : "github-light",
				});
				setHighlightedCode(html);
			} catch {
				// Fallback for unsupported languages
				setHighlightedCode(`<pre><code>${escapeHtml(code)}</code></pre>`);
			}
		};

		highlight();
	}, [code, language, resolvedTheme, mounted]);

	const handleCopy = useCallback(async () => {
		try {
			await navigator.clipboard.writeText(code);
			setCopied(true);
			setTimeout(() => setCopied(false), 2000);
		} catch (err) {
			console.error("Failed to copy:", err);
		}
	}, [code]);

	return (
		<div
			className={ANIMATION_CLASSES.fadeInUp}
			style={getStaggerStyle(
				animationIndex,
				STAGGER_PRESETS.formFields.baseDelay,
				STAGGER_PRESETS.formFields.increment,
				STAGGER_PRESETS.formFields.duration,
			)}
		>
			{title && (
				<h3 className="mb-2 text-base font-medium text-foreground">{title}</h3>
			)}

			{description && (
				<p className="mb-2 text-sm text-muted-foreground">{description}</p>
			)}

			<div className="relative group">
				<div
					className={cx(
						"rounded-lg border border-border bg-muted/50 overflow-hidden",
						showLineNumbers &&
							"[&_pre]:!pl-12 [&_.line]:relative [&_.line]:before:absolute [&_.line]:before:-left-8 [&_.line]:before:w-6 [&_.line]:before:text-right [&_.line]:before:text-muted-foreground/50 [&_.line]:before:text-xs [&_.line]:before:content-[counter(line)] [&_pre]:counter-reset-[line] [&_.line]:counter-increment-[line]",
					)}
				>
					{mounted && highlightedCode ? (
						<div
							className="[&_pre]:!bg-transparent [&_pre]:p-4 [&_pre]:overflow-x-auto [&_pre]:text-sm [&_code]:text-sm"
							dangerouslySetInnerHTML={{ __html: highlightedCode }}
						/>
					) : (
						<pre className="p-4 overflow-x-auto text-sm">
							<code className="text-foreground">{code}</code>
						</pre>
					)}
				</div>

				{showCopyButton && (
					<button
						type="button"
						className="absolute top-2 right-2 p-2 rounded-md text-muted-foreground hover:text-foreground hover:bg-muted transition-colors"
						onClick={handleCopy}
						aria-label={copied ? copiedText : copyButtonText}
					>
						{copied ? (
							<Check className="h-4 w-4 text-green-500" />
						) : (
							<Copy className="h-4 w-4" />
						)}
					</button>
				)}
			</div>
		</div>
	);
}

// Helper to escape HTML for fallback
function escapeHtml(text: string): string {
	return text
		.replace(/&/g, "&amp;")
		.replace(/</g, "&lt;")
		.replace(/>/g, "&gt;")
		.replace(/"/g, "&quot;")
		.replace(/'/g, "&#039;");
}
