import { useEffect, useRef, useState, useCallback, useMemo } from "react";
import { useParams, useNavigate } from "react-router-dom";
import { toast } from "sonner";
import { BookOpen, Upload } from "lucide-react";
import * as api from "@/api/client";
import { autocompletion } from "@codemirror/autocomplete";
import type { Extension } from "@codemirror/state";
import { useEditorStore } from "@/stores/editorStore";
import { usePagesStore } from "@/stores/pagesStore";
import { useUnsavedGuard } from "@/hooks/useUnsavedGuard";
import { useCompile } from "@/hooks/useCompile";
import { uframeHighlight } from "@/components/editor/uframeHighlight";
import { uframeCommandSource, uframeValueHintSource, loadCommandsFromApi } from "@/components/editor/uframeCommands";
import { keywordHoverTooltip } from "@/components/editor/uframeHover";
import EditorPane from "@/components/editor/EditorPane";
import EditorPointer from "@/components/editor/EditorPointer";
import PreviewPane from "@/components/editor/PreviewPane";
import ToolBar from "@/components/editor/ToolBar";
import { EXAMPLES } from "@/components/editor/examples";
import {
  Popover,
  PopoverTrigger,
  PopoverContent,
  PopoverHeader,
  PopoverTitle,
} from "@/components/ui/popover";
import {
  ResizablePanelGroup,
  ResizablePanel,
  ResizableHandle,
} from "@/components/ui/resizable";

export default function EditorView() {
  const { name } = useParams<{ name: string }>();
  const navigate = useNavigate();
  const isNew = !name;

  const ufSource = useEditorStore((s) => s.ufSource);
  const isDirty = useEditorStore((s) => s.isDirty);
  const setSource = useEditorStore((s) => s.setSource);
  const setDirty = useEditorStore((s) => s.setDirty);
  const setCurrentPage = useEditorStore((s) => s.setCurrentPage);
  const reset = useEditorStore((s) => s.reset);

  const { fetchPages } = usePagesStore();
  const [pageName, setPageName] = useState(name ?? "");
  const [saving, setSaving] = useState(false);

  // µFrame extensions: syntax highlighting + slash commands
  const extensions = useMemo(
    () => [
      ...uframeHighlight(),
      autocompletion({
        override: [uframeCommandSource, uframeValueHintSource],
        icons: false,
        activateOnTyping: true,
      }),
      keywordHoverTooltip,
    ],
    [],
  );

  // Load DSL commands from backend registry on mount
  useEffect(() => {
    loadCommandsFromApi();
  }, []);

  // Auto-compile on source changes
  useCompile();
  useUnsavedGuard();

  // Fetch pages for backlinks
  useEffect(() => {
    fetchPages();
  }, []);

  // Load page on mount / route change
  useEffect(() => {
    reset();
    if (name) {
      setPageName(name);
      api.fetchPage(name).then((data) => {
        if (data.source != null) {
          useEditorStore.setState({
            ufSource: data.source,
            isDirty: false,
          });
        }
      });
    }
    return () => reset();
  }, [name]);

  const handleSave = useCallback(
    async (publish: boolean) => {
      const slug = pageName
        .trim()
        .toLowerCase()
        .replace(/[^a-z0-9_-]/g, "-");
      if (!slug) {
        toast.error("Enter a page name.");
        return;
      }
      setSaving(true);
      try {
        const meta = await api.savePage(slug, ufSource, publish);
        setCurrentPage(meta);
        setDirty(false);
        fetchPages();
        toast.success(publish ? "Published" : "Draft saved");
        if (isNew) navigate(`/editor/${slug}`, { replace: true });
      } catch (e) {
        toast.error(`Save failed: ${e}`);
      } finally {
        setSaving(false);
      }
    },
    [pageName, ufSource, isNew, navigate],
  );

  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if ((e.metaKey || e.ctrlKey) && e.key === "s") {
        e.preventDefault();
        handleSave(false);
      }
      if ((e.metaKey || e.ctrlKey) && e.key === "p") {
        e.preventDefault();
        handleSave(true);
      }
    };
    window.addEventListener("keydown", handler);
    return () => window.removeEventListener("keydown", handler);
  }, [handleSave]);

  return (
    <div className="flex flex-col h-full">
      <EditorPointer />
      <div className="flex flex-col flex-1 min-h-0">
        <ToolBar
          pageName={pageName}
          onNameChange={isNew ? setPageName : undefined}
          onSaveDraft={() => handleSave(false)}
          onPublish={() => handleSave(true)}
          saving={saving}
          isDirty={isDirty}
        />
        <ResizablePanelGroup orientation="horizontal" className="flex-1 min-h-0">
          <ResizablePanel defaultSize={50} minSize={20}>
            <SourcePane
              ufSource={ufSource}
              setSource={setSource}
              extensions={extensions}
            />
          </ResizablePanel>
          <ResizableHandle />
          <ResizablePanel defaultSize={50} minSize={20}>
            <PreviewPane />
          </ResizablePanel>
        </ResizablePanelGroup>
      </div>
    </div>
  );
}


/** Source pane — editor with header bar matching the Preview pane */
function SourcePane({
  ufSource,
  setSource,
  extensions,
}: {
  ufSource: string;
  setSource: (s: string) => void;
  extensions: Extension[];
}) {
  const [examplesOpen, setExamplesOpen] = useState(false);
  const fileRef = useRef<HTMLInputElement>(null);
  const [uploading, setUploading] = useState(false);

  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;
    setUploading(true);
    try {
      const data = await api.uploadImage(file);
      toast.success(`Uploaded ${data.filename}`);
      setSource(`image "${data.path}" braille 30\n  align center`);
    } catch (err) {
      toast.error(`Upload failed: ${err}`);
    } finally {
      setUploading(false);
      if (fileRef.current) fileRef.current.value = "";
    }
  };

  return (
    <div className="flex flex-col h-full">
      <div className="flex items-center px-4 py-2 border-b-2 border-border shrink-0 gap-2">
        <span className="font-medium text-foreground flex-1">Source</span>

        <Popover open={examplesOpen} onOpenChange={setExamplesOpen}>
          <PopoverTrigger
            render={
              <button className="text-[10px] text-muted-foreground hover:text-foreground transition-colors uppercase tracking-wider flex items-center gap-1 cursor-pointer">
                <BookOpen className="h-3 w-3" />
                Examples
              </button>
            }
          />
          <PopoverContent side="bottom" align="end" sideOffset={8}>
            <PopoverHeader>
              <PopoverTitle>Insert Example</PopoverTitle>
            </PopoverHeader>
            <div className="flex flex-col gap-0.5 max-h-72 overflow-y-auto -mx-1">
              {EXAMPLES.map((ex) => (
                <button
                  key={ex.name}
                  onClick={() => { setSource(ex.source); setExamplesOpen(false); }}
                  className="flex flex-col items-start px-2 py-1.5 text-left hover:bg-accent transition-colors cursor-pointer"
                >
                  <span className="text-sm font-medium">{ex.name}</span>
                  <span className="text-xs text-muted-foreground leading-tight">{ex.description}</span>
                </button>
              ))}
            </div>
          </PopoverContent>
        </Popover>

        <input ref={fileRef} type="file" accept="image/*" className="hidden" onChange={handleUpload} />
        <button
          onClick={() => fileRef.current?.click()}
          disabled={uploading}
          className="text-[10px] text-muted-foreground hover:text-foreground transition-colors uppercase tracking-wider flex items-center gap-1 disabled:opacity-50 cursor-pointer"
        >
          <Upload className="h-3 w-3" />
          {uploading ? "Uploading…" : "Image"}
        </button>
      </div>
      <div className="flex-1 overflow-auto min-h-0">
        <EditorPane value={ufSource} onChange={setSource} extensions={extensions} />
      </div>
    </div>
  );
}
