import { useEffect, useRef, useCallback, useImperativeHandle, forwardRef } from "react";
import { EditorView, keymap, lineNumbers, highlightActiveLineGutter, highlightSpecialChars, drawSelection, dropCursor, rectangularSelection, crosshairCursor, highlightActiveLine } from "@codemirror/view";
import { EditorState } from "@codemirror/state";
import { history, defaultKeymap, historyKeymap, indentWithTab } from "@codemirror/commands";
import { foldGutter, indentOnInput, syntaxHighlighting, defaultHighlightStyle, bracketMatching, foldKeymap } from "@codemirror/language";
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap } from "@codemirror/autocomplete";
import { searchKeymap, highlightSelectionMatches } from "@codemirror/search";
import { lintKeymap } from "@codemirror/lint";
import { vscodeDark, vscodeLight } from "@uiw/codemirror-theme-vscode";
import { actions, useStore } from "@/lib/store";
import { getLanguageExtension } from "@/lib/languageDetect";
import type { Extension } from "@codemirror/state";

export interface EditorHandle {
  getView(): EditorView | null;
  goToLine(line: number): void;
}

interface EditorProps {
  tabPath?: string; // if provided, use this instead of store.activeTabPath (for split view)
}

export const Editor = forwardRef<EditorHandle, EditorProps>(function Editor({ tabPath }, ref) {
  const containerRef = useRef<HTMLDivElement>(null);
  const viewRef = useRef<EditorView | null>(null);
  const store = useStore();
  const effectivePath = tabPath ?? store.activeTabPath;
  const activeTab = store.tabs.find((t) => t.path === effectivePath);
  const currentPathRef = useRef<string | null>(null);

  useImperativeHandle(ref, () => ({
    getView() {
      return viewRef.current;
    },
    goToLine(line: number) {
      const view = viewRef.current;
      if (!view) return;
      const doc = view.state.doc;
      const lineNum = Math.max(1, Math.min(line, doc.lines));
      const pos = doc.line(lineNum).from;
      view.dispatch({
        selection: { anchor: pos },
        scrollIntoView: true,
      });
      view.focus();
    },
  }));

  const createView = useCallback(async (content: string, language: string, path: string) => {
    if (!containerRef.current) return;

    if (viewRef.current) {
      viewRef.current.destroy();
      viewRef.current = null;
    }

    const langExt = await getLanguageExtension(language);
    const theme = store.settings.theme === "light" ? vscodeLight : vscodeDark;
    const extensions: Extension[] = [
      lineNumbers(),
      highlightActiveLineGutter(),
      highlightSpecialChars(),
      history(),
      foldGutter(),
      drawSelection(),
      dropCursor(),
      EditorState.allowMultipleSelections.of(true),
      indentOnInput(),
      syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
      bracketMatching(),
      closeBrackets(),
      autocompletion(),
      rectangularSelection(),
      crosshairCursor(),
      highlightActiveLine(),
      highlightSelectionMatches(),
      keymap.of([
        ...closeBracketsKeymap,
        ...defaultKeymap,
        ...searchKeymap,
        ...historyKeymap,
        ...foldKeymap,
        ...completionKeymap,
        ...lintKeymap,
        indentWithTab,
      ]),
      theme,
      EditorState.tabSize.of(store.settings.tabSize),
      EditorView.theme({
        "&": {
          fontSize: store.settings.fontSize + "px",
          fontFamily: store.settings.fontFamily,
        },
        ".cm-content": {
          fontFamily: store.settings.fontFamily,
        },
        ".cm-gutters": {
          fontFamily: store.settings.fontFamily,
        },
      }),
      EditorView.updateListener.of((update) => {
        if (update.docChanged) {
          actions.updateContent(path, update.state.doc.toString());
        }
        if (update.selectionSet && !tabPath) {
          const pos = update.state.selection.main.head;
          const line = update.state.doc.lineAt(pos);
          actions.setCursor(line.number, pos - line.from + 1);
        }
      }),
    ];

    if (store.settings.wordWrap) {
      extensions.push(EditorView.lineWrapping);
    }

    if (langExt) {
      extensions.push(langExt);
    }

    const state = EditorState.create({
      doc: content,
      extensions,
    });

    viewRef.current = new EditorView({
      state,
      parent: containerRef.current,
    });

    currentPathRef.current = path;
  }, [store.settings.fontSize, store.settings.fontFamily, store.settings.tabSize, store.settings.wordWrap, store.settings.theme, tabPath]);

  useEffect(() => {
    if (!activeTab) {
      if (viewRef.current) {
        viewRef.current.destroy();
        viewRef.current = null;
        currentPathRef.current = null;
      }
      return;
    }

    if (currentPathRef.current !== activeTab.path) {
      createView(activeTab.content, activeTab.language, activeTab.path);
    }
  }, [activeTab, createView]);

  useEffect(() => {
    return () => {
      if (viewRef.current) {
        viewRef.current.destroy();
      }
    };
  }, []);

  if (!activeTab) {
    return null;
  }

  return <div ref={containerRef} className="h-full w-full overflow-hidden" />;
});
