import { useCallback, useMemo } from "react";
import { LogLevel } from "@codingame/monaco-vscode-api";
import {
  MonacoEditorReactComp,
} from "@typefox/monaco-editor-react";
import type { MonacoVscodeApiConfig } from "monaco-languageclient/vscodeApiWrapper";
import type { EditorAppConfig, TextContents } from "monaco-languageclient/editorApp";
import type { LanguageClientConfig } from "monaco-languageclient/lcwrapper";
import { configureDefaultWorkerFactory } from "monaco-languageclient/workerFactory";
import "../../nwscript-extension/index.js";

function getVscodeApiConfig(): MonacoVscodeApiConfig {
  return {
    $type: "extended",
    viewsConfig: {
      $type: "EditorService",
    },
    userConfiguration: {
      json: JSON.stringify({
        "workbench.colorTheme": "Default Dark Modern",
        "workbench.colorCustomizations": {
          "editor.background": "#231e17",
          "editor.foreground": "#ece8e3",
          "editor.lineHighlightBackground": "#302a2040",
          "editor.selectionBackground": "#3d3018",
          "editor.selectionHighlightBackground": "#3d301860",
          "editor.inactiveSelectionBackground": "#3d301850",
          "editor.findMatchBackground": "#b07a0040",
          "editor.findMatchHighlightBackground": "#b07a0025",
          "editor.hoverHighlightBackground": "#3d301830",
          "editorCursor.foreground": "#b07a00",
          "editorWhitespace.foreground": "#4a403550",
          "editorIndentGuide.background": "#4a403530",
          "editorIndentGuide.activeBackground": "#4a403580",
          "editorLineNumber.foreground": "#a69f9650",
          "editorLineNumber.activeForeground": "#ece8e3",
          "editorBracketMatch.background": "#3d301840",
          "editorBracketMatch.border": "#b07a0080",
          "editorOverviewRuler.border": "#4a4035",
          "editorGutter.background": "#231e17",
          "editorWidget.background": "#3b3328",
          "editorWidget.foreground": "#ece8e3",
          "editorWidget.border": "#4a4035",
          "editorSuggestWidget.background": "#3b3328",
          "editorSuggestWidget.border": "#4a4035",
          "editorSuggestWidget.foreground": "#ece8e3",
          "editorSuggestWidget.highlightForeground": "#b07a00",
          "editorSuggestWidget.selectedBackground": "#3d3018",
          "editorHoverWidget.background": "#3b3328",
          "editorHoverWidget.border": "#4a4035",
          "editorGroupHeader.tabsBackground": "#302a20",
          "editorGroupHeader.tabsBorder": "#4a4035",
          "editorGroup.border": "#4a4035",
          "tab.activeBackground": "#231e17",
          "tab.activeForeground": "#ece8e3",
          "tab.activeBorderTop": "#b07a00",
          "tab.inactiveBackground": "#302a20",
          "tab.inactiveForeground": "#a69f96",
          "tab.border": "#4a4035",
          "input.background": "#231e17",
          "input.foreground": "#ece8e3",
          "input.border": "#4a4035",
          "input.placeholderForeground": "#a69f9680",
          "inputOption.activeBorder": "#b07a00",
          "dropdown.background": "#3b3328",
          "dropdown.foreground": "#ece8e3",
          "dropdown.border": "#4a4035",
          "list.activeSelectionBackground": "#3d3018",
          "list.activeSelectionForeground": "#ece8e3",
          "list.inactiveSelectionBackground": "#3d301880",
          "list.hoverBackground": "#302a2080",
          "list.highlightForeground": "#b07a00",
          "scrollbarSlider.background": "#4a403540",
          "scrollbarSlider.hoverBackground": "#4a403580",
          "scrollbarSlider.activeBackground": "#4a4035a0",
          "focusBorder": "#b07a0080",
          "peekView.border": "#b07a00",
          "peekViewEditor.background": "#231e17",
          "peekViewResult.background": "#302a20",
          "peekViewTitle.background": "#302a20",
          "minimap.selectionHighlight": "#3d3018",
          "minimap.findMatchHighlight": "#b07a0060",
        },
        "editor.fontSize": 14,
        "editor.fontFamily": "'JetBrains Mono Variable', 'Fira Code', monospace",
        "editor.tabSize": 4,
        "editor.insertSpaces": true,
        "editor.minimap.enabled": false,
        "editor.scrollBeyondLastLine": false,
        "editor.wordWrap": "off",
        "editor.renderWhitespace": "selection",
        "editor.bracketPairColorization.enabled": true,
        "editor.padding.top": 8,
        "editor.lineNumbers": "on",
        "editor.guides.bracketPairsHorizontal": "active",
        "editor.wordBasedSuggestions": "off",
        "editor.quickSuggestions": true,
        "editor.parameterHints.enabled": true,
      }),
    },
    monacoWorkerFactory: configureDefaultWorkerFactory,
  };
}

function languageFromPath(filePath: string): string {
  const ext = filePath.split(".").pop()?.toLowerCase();
  const map: Record<string, string> = {
    nss: "nwscript",
    json: "json",
    sql: "sql",
    css: "css",
    html: "html",
    xml: "xml",
    js: "javascript",
    ts: "typescript",
    md: "markdown",
    txt: "plaintext",
    "2da": "plaintext",
    cfg: "ini",
    sh: "shellscript",
  };
  return map[ext ?? ""] ?? "plaintext";
}

interface MonacoEditorProps {
  filePath: string;
  content: string;
  language?: string;
  onChange?: (value: string) => void;
  workspacePath?: string;
}

export function MonacoEditor({
  filePath,
  content,
  language,
  onChange,
  workspacePath,
}: MonacoEditorProps) {
  const resolvedLang = language ?? languageFromPath(filePath);
  const isNwscript = resolvedLang === "nwscript";

  const fileUri = workspacePath
    ? `file://${workspacePath}/repos/nwn-module/${filePath}`
    : `file:///workspace/repos/nwn-module/${filePath}`;

  const editorAppConfig = useMemo<EditorAppConfig>(
    () => ({
      codeResources: {
        modified: {
          text: content,
          uri: fileUri,
          enforceLanguageId: resolvedLang,
        },
      },
      editorOptions: {
        automaticLayout: true,
      },
    }),
    [filePath],
  );

  const languageClientConfig = useMemo<LanguageClientConfig | undefined>(() => {
    if (!isNwscript) return undefined;
    const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
    return {
      languageId: "nwscript",
      connection: {
        options: {
          $type: "WebSocketUrl" as const,
          url: `${protocol}//${window.location.host}/ws/lsp`,
        },
      },
      clientOptions: {
        documentSelector: ["nwscript"],
        workspaceFolder: workspacePath
          ? {
              index: 0,
              name: "nwn-module",
              uri: { scheme: "file", path: `${workspacePath}/repos/nwn-module` } as any,
            }
          : undefined,
      },
    };
  }, [isNwscript, workspacePath]);

  const handleTextChanged = useCallback(
    (textChanges: TextContents) => {
      if (textChanges.modified !== undefined) {
        onChange?.(textChanges.modified);
      }
    },
    [onChange],
  );

  const handleError = useCallback((error: Error) => {
    console.error("[MonacoEditor]", error.message, error.stack);
  }, []);

  return (
    <MonacoEditorReactComp
      style={{ width: "100%", height: "100%" }}
      vscodeApiConfig={getVscodeApiConfig()}
      editorAppConfig={editorAppConfig}
      languageClientConfig={languageClientConfig}
      onTextChanged={handleTextChanged}
      onError={handleError}
      logLevel={LogLevel.Warning}
    />
  );
}
