import { memo, useCallback, useMemo, useState, useEffect } from "react";
import { motion, AnimatePresence } from "motion/react";
import { Check, Copy, PanelRightClose, Code2, Eye } from "lucide-react";
import { Button } from "@/components/ui/button";
import { MarkdownRenderer } from "@/components/MarkdownRenderer";
import { useCodePreview } from "./code-preview-context";

const PREVIEW_LANGUAGES = new Set(["html", "markdown", "md", "latex", "tex"]);

function canPreview(language: string): boolean {
  return PREVIEW_LANGUAGES.has(language.toLowerCase());
}

type ViewMode = "code" | "preview";

export const CodePreviewPanel = memo(function CodePreviewPanel() {
  const { activeCode, closeCodePreview } = useCodePreview();
  const [copied, setCopied] = useState(false);
  const [viewMode, setViewMode] = useState<ViewMode>("code");

  const language = activeCode?.language?.toLowerCase() ?? "";
  const showPreviewToggle = canPreview(language);

  useEffect(() => {
    if (activeCode) setViewMode("code");
  }, [activeCode?.id]);

  const lines = useMemo(
    () => (activeCode?.code ?? "").replace(/\n$/, "").split("\n"),
    [activeCode?.code],
  );

  const handleCopy = useCallback(() => {
    if (!activeCode?.code) return;
    navigator.clipboard.writeText(activeCode.code).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1600);
    });
  }, [activeCode?.code]);

  const isOpen = activeCode !== null;
  const isHTML = language === "html";
  const isLatex = language === "latex" || language === "tex";
  const isMarkdown = language === "markdown" || language === "md";

  return (
    <AnimatePresence>
      {isOpen && (
        <motion.aside
          initial={{ width: 0, opacity: 0 }}
          animate={{
            width: "min(48vw, 760px)",
            opacity: 1,
          }}
          exit={{ width: 0, opacity: 0 }}
          transition={{ duration: 0.3, ease: [0.25, 0.46, 0.45, 0.94] }}
          className="flex h-full shrink-0 flex-col overflow-hidden border-l border-border/60 bg-card/95 shadow-[-4px_0_24px_-8px_rgba(0,0,0,0.06)] backdrop-blur-sm"
        >
          <div className="flex h-full w-full flex-col">
            {/* Header */}
            <div className="flex h-11 shrink-0 items-center justify-between gap-3 border-b border-border/40 bg-muted/20 px-4">
              <div className="flex min-w-0 items-center gap-2.5">
                <div className="grid size-7 place-items-center rounded-lg bg-primary/10">
                  <Code2 className="size-3.5 text-primary/70" />
                </div>
                <div className="min-w-0">
                  <div className="truncate text-sm font-medium text-foreground">
                    {activeCode?.title || activeCode?.language || "Code"}
                  </div>
                  <div className="text-[11px] text-muted-foreground/60">
                    {activeCode?.subtitle ??
                      `${activeCode?.lineCount ?? lines.length} line${(activeCode?.lineCount ?? lines.length) !== 1 ? "s" : ""}`}
                  </div>
                </div>
              </div>

              <div className="flex items-center gap-1">
                {/* Code / Preview toggle */}
                {showPreviewToggle && (
                  <div className="mr-1.5 flex items-center overflow-hidden rounded-lg border border-border/60 bg-muted/30 p-0.5">
                    <button
                      className={`flex items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium transition-[background-color,border-color,color,box-shadow] ${
                        viewMode === "code"
                          ? "bg-card text-foreground shadow-sm"
                          : "text-muted-foreground/60 hover:text-foreground"
                      }`}
                      onClick={() => setViewMode("code")}
                      type="button"
                    >
                      <Code2 className="size-3" />
                      Code
                    </button>
                    <button
                      className={`flex items-center gap-1 rounded-md px-2 py-1 text-[11px] font-medium transition-[background-color,border-color,color,box-shadow] ${
                        viewMode === "preview"
                          ? "bg-card text-foreground shadow-sm"
                          : "text-muted-foreground/60 hover:text-foreground"
                      }`}
                      onClick={() => setViewMode("preview")}
                      type="button"
                    >
                      <Eye className="size-3" />
                      Preview
                    </button>
                  </div>
                )}

                <Button
                  className="size-8"
                  disabled={!activeCode}
                  onClick={handleCopy}
                  size="icon"
                  variant="ghost"
                  aria-label={copied ? "Copied" : "Copy code"}
                >
                  {copied ? (
                    <Check className="size-4 text-emerald-500" />
                  ) : (
                    <Copy className="size-4" />
                  )}
                </Button>
                <Button
                  className="size-8"
                  onClick={closeCodePreview}
                  size="icon"
                  variant="ghost"
                  aria-label="Close code preview"
                >
                  <PanelRightClose className="size-4" />
                </Button>
              </div>
            </div>

            {/* Content */}
            <div className="min-h-0 flex-1 overflow-auto">
              {viewMode === "preview" ? (
                <PreviewContent
                  code={activeCode?.code ?? ""}
                  isHTML={isHTML}
                  isLatex={isLatex}
                  isMarkdown={isMarkdown}
                />
              ) : (
                <div className="grid min-w-max grid-cols-[auto_1fr]">
                  {/* Line numbers */}
                  <div
                    aria-hidden="true"
                    className="select-none border-r border-border/30 bg-muted/15 px-3 py-4 text-right font-mono text-[11px] tabular-nums leading-[1.7] text-muted-foreground/30"
                  >
                    {lines.map((_, i) => (
                      <div key={i}>{i + 1}</div>
                    ))}
                  </div>
                  {/* Code */}
                  <pre className="m-0 overflow-x-auto px-4 py-4 font-mono text-[13px] leading-[1.7] text-foreground/85">
                    <code>{activeCode?.code ?? ""}</code>
                  </pre>
                </div>
              )}
            </div>
          </div>
        </motion.aside>
      )}
    </AnimatePresence>
  );
});

/** Renders code content as a preview. */
const PreviewContent = memo(function PreviewContent({
  code,
  isHTML,
  isLatex,
  isMarkdown,
}: {
  code: string;
  isHTML: boolean;
  isLatex: boolean;
  isMarkdown: boolean;
}) {
  if (isHTML) {
    return (
      <iframe
        className="h-full w-full border-0"
        sandbox="allow-scripts allow-same-origin"
        srcDoc={code}
        title="HTML Preview"
      />
    );
  }

  if (isMarkdown) {
    return (
      <div className="px-6 py-5">
        <MarkdownRenderer content={code} />
      </div>
    );
  }

  if (isLatex) {
    return (
      <div className="px-6 py-5">
        <pre className="whitespace-pre-wrap font-mono text-sm text-foreground/80">
          {code}
        </pre>
        <p className="mt-4 text-xs text-muted-foreground/50">
          LaTeX rendering requires a math engine (KaTeX / MathJax).
        </p>
      </div>
    );
  }

  return (
    <pre className="whitespace-pre-wrap p-5 font-mono text-sm text-foreground/80">
      {code}
    </pre>
  );
});
