"use client"

import { useEffect, useState } from "react"
import type { BeforeMount } from "@monaco-editor/react"

export const MONACO_LIGHT_THEME = "codeg-light"
export const MONACO_DARK_THEME = "codeg-dark"

export const monacoTokenRules = {
  light: [
    { token: "diff.header", foreground: "52525B", fontStyle: "bold" },
    { token: "diff.meta", foreground: "71717A" },
    { token: "diff.range", foreground: "0369A1", fontStyle: "bold" },
    { token: "diff.file", foreground: "334155" },
    { token: "diff.inserted", foreground: "166534" },
    { token: "diff.deleted", foreground: "991B1B" },
    { token: "diff.context", foreground: "3F3F46" },
  ],
  dark: [
    { token: "diff.header", foreground: "D4D4D8", fontStyle: "bold" },
    { token: "diff.meta", foreground: "A1A1AA" },
    { token: "diff.range", foreground: "7DD3FC", fontStyle: "bold" },
    { token: "diff.file", foreground: "D4D4D8" },
    { token: "diff.inserted", foreground: "86EFAC" },
    { token: "diff.deleted", foreground: "FDA4AF" },
    { token: "diff.context", foreground: "E4E4E7" },
  ],
}

export const monacoThemeColors = {
  light: {
    focusBorder: "#a1a1aa",
    "editor.background": "#ffffff",
    "editor.foreground": "#09090b",
    "editorGutter.background": "#ffffff",
    "editorLineNumber.foreground": "#a1a1aa",
    "editorLineNumber.activeForeground": "#18181b",
    "editor.lineHighlightBackground": "#f4f4f5",
    "editor.selectionBackground": "#e4e4e7",
    "editor.inactiveSelectionBackground": "#f4f4f5",
    "editorWidget.background": "#ffffff",
    "editorWidget.foreground": "#09090b",
    "editorWidget.border": "#e4e4e7",
    "editorHoverWidget.background": "#ffffff",
    "editorHoverWidget.foreground": "#09090b",
    "editorHoverWidget.border": "#e4e4e7",
    "editorHoverWidget.statusBarBackground": "#f4f4f5",
    "editorSuggestWidget.background": "#ffffff",
    "editorSuggestWidget.border": "#e4e4e7",
    "editorSuggestWidget.foreground": "#09090b",
    "editorSuggestWidget.highlightForeground": "#18181b",
    "editorSuggestWidget.selectedBackground": "#f4f4f5",
    "menu.background": "#ffffff",
    "menu.foreground": "#09090b",
    "menu.selectionBackground": "#f4f4f5",
    "menu.selectionForeground": "#09090b",
    "menu.separatorBackground": "#e4e4e7",
    "menu.border": "#e4e4e7",
    "input.background": "#ffffff",
    "input.foreground": "#09090b",
    "input.border": "#e4e4e7",
    "dropdown.background": "#ffffff",
    "dropdown.foreground": "#09090b",
    "dropdown.border": "#e4e4e7",
    "list.hoverBackground": "#f4f4f5",
    "list.activeSelectionBackground": "#f4f4f5",
    "list.activeSelectionForeground": "#09090b",
    "list.inactiveSelectionBackground": "#f4f4f5",
    "list.inactiveSelectionForeground": "#09090b",
    "list.focusOutline": "#a1a1aa",
    "peekView.border": "#e4e4e7",
    "peekViewEditor.background": "#ffffff",
    "peekViewEditor.matchHighlightBackground": "#e4e4e7",
    "peekViewEditorGutter.background": "#ffffff",
    "peekViewResult.background": "#ffffff",
    "peekViewResult.fileForeground": "#09090b",
    "peekViewResult.lineForeground": "#71717a",
    "peekViewResult.matchHighlightBackground": "#e4e4e7",
    "peekViewResult.selectionBackground": "#f4f4f5",
    "peekViewResult.selectionForeground": "#09090b",
    "peekViewTitle.background": "#f4f4f5",
    "peekViewTitleLabel.foreground": "#09090b",
    "peekViewTitleDescription.foreground": "#71717a",
  },
  dark: {
    focusBorder: "#71717a",
    "editor.background": "#171717",
    "editor.foreground": "#fafafa",
    "editorGutter.background": "#171717",
    "editorLineNumber.foreground": "#71717a",
    "editorLineNumber.activeForeground": "#fafafa",
    "editor.lineHighlightBackground": "#27272a",
    "editor.selectionBackground": "#3f3f46",
    "editor.inactiveSelectionBackground": "#27272a",
    "editorWidget.background": "#18181b",
    "editorWidget.foreground": "#fafafa",
    "editorWidget.border": "#27272a",
    "editorHoverWidget.background": "#18181b",
    "editorHoverWidget.foreground": "#fafafa",
    "editorHoverWidget.border": "#27272a",
    "editorHoverWidget.statusBarBackground": "#27272a",
    "editorSuggestWidget.background": "#18181b",
    "editorSuggestWidget.border": "#27272a",
    "editorSuggestWidget.foreground": "#fafafa",
    "editorSuggestWidget.highlightForeground": "#ffffff",
    "editorSuggestWidget.selectedBackground": "#27272a",
    "menu.background": "#18181b",
    "menu.foreground": "#fafafa",
    "menu.selectionBackground": "#27272a",
    "menu.selectionForeground": "#fafafa",
    "menu.separatorBackground": "#3f3f46",
    "menu.border": "#27272a",
    "input.background": "#18181b",
    "input.foreground": "#fafafa",
    "input.border": "#27272a",
    "dropdown.background": "#18181b",
    "dropdown.foreground": "#fafafa",
    "dropdown.border": "#27272a",
    "list.hoverBackground": "#27272a",
    "list.activeSelectionBackground": "#27272a",
    "list.activeSelectionForeground": "#fafafa",
    "list.inactiveSelectionBackground": "#27272a",
    "list.inactiveSelectionForeground": "#fafafa",
    "list.focusOutline": "#71717a",
    "peekView.border": "#27272a",
    "peekViewEditor.background": "#171717",
    "peekViewEditor.matchHighlightBackground": "#3f3f46",
    "peekViewEditorGutter.background": "#171717",
    "peekViewResult.background": "#18181b",
    "peekViewResult.fileForeground": "#fafafa",
    "peekViewResult.lineForeground": "#a1a1aa",
    "peekViewResult.matchHighlightBackground": "#3f3f46",
    "peekViewResult.selectionBackground": "#27272a",
    "peekViewResult.selectionForeground": "#fafafa",
    "peekViewTitle.background": "#27272a",
    "peekViewTitleLabel.foreground": "#fafafa",
    "peekViewTitleDescription.foreground": "#a1a1aa",
  },
}

export const defineDiffLanguage: BeforeMount = (monaco) => {
  const hasDiffLanguage = monaco.languages
    .getLanguages()
    .some((language: { id: string }) => language.id === "diff")

  if (!hasDiffLanguage) {
    monaco.languages.register({ id: "diff" })
  }

  monaco.languages.setMonarchTokensProvider("diff", {
    defaultToken: "diff.context",
    tokenizer: {
      root: [
        [/^diff --git .*$/, "diff.header"],
        [/^index .*$/, "diff.meta"],
        [/^@@ .*@@.*$/, "diff.range"],
        [/^(?:\+\+\+|---) .*$/, "diff.file"],
        [/^\+.*$/, "diff.inserted"],
        [/^-.*$/, "diff.deleted"],
        [/^\\ No newline at end of file$/, "diff.meta"],
        [/^Binary files .* differ$/, "diff.meta"],
        [/^.*$/, "diff.context"],
      ],
    },
  })
}

/**
 * Override Monaco's built-in Python tokenizer to fix triple-quoted string
 * handling. The default monarch tokenizer doesn't correctly parse `f"""..."""`
 * or `"""..."""`, causing everything after the closing quotes to be highlighted
 * as a string.
 */
const fixPythonTripleQuotes: BeforeMount = (monaco) => {
  monaco.languages.setMonarchTokensProvider("python", {
    defaultToken: "",
    keywords: [
      "False",
      "None",
      "True",
      "and",
      "as",
      "assert",
      "async",
      "await",
      "break",
      "class",
      "continue",
      "def",
      "del",
      "elif",
      "else",
      "except",
      "finally",
      "for",
      "from",
      "global",
      "if",
      "import",
      "in",
      "is",
      "lambda",
      "nonlocal",
      "not",
      "or",
      "pass",
      "raise",
      "return",
      "try",
      "while",
      "with",
      "yield",
    ],
    builtins: [
      "abs",
      "all",
      "any",
      "bin",
      "bool",
      "breakpoint",
      "bytearray",
      "bytes",
      "callable",
      "chr",
      "classmethod",
      "compile",
      "complex",
      "delattr",
      "dict",
      "dir",
      "divmod",
      "enumerate",
      "eval",
      "exec",
      "filter",
      "float",
      "format",
      "frozenset",
      "getattr",
      "globals",
      "hasattr",
      "hash",
      "help",
      "hex",
      "id",
      "input",
      "int",
      "isinstance",
      "issubclass",
      "iter",
      "len",
      "list",
      "locals",
      "map",
      "max",
      "memoryview",
      "min",
      "next",
      "object",
      "oct",
      "open",
      "ord",
      "pow",
      "print",
      "property",
      "range",
      "repr",
      "reversed",
      "round",
      "set",
      "setattr",
      "slice",
      "sorted",
      "staticmethod",
      "str",
      "sum",
      "super",
      "tuple",
      "type",
      "vars",
      "zip",
    ],
    brackets: [
      { open: "{", close: "}", token: "delimiter.curly" },
      { open: "[", close: "]", token: "delimiter.bracket" },
      { open: "(", close: ")", token: "delimiter.parenthesis" },
    ],
    tokenizer: {
      root: [
        // decorators
        [/^(\s*)(@\w+)/, ["white", "tag"]],
        // triple-quoted strings (must come before single-quoted)
        [/(?:[fFrRbBuU]{1,2})?"""/, "string", "@tdqs"],
        [/(?:[fFrRbBuU]{1,2})?'''/, "string", "@tsqs"],
        // single-line strings
        [/(?:[fFrRbBuU]{1,2})?"([^"\\]|\\.)*$/, "string.invalid"],
        [/(?:[fFrRbBuU]{1,2})?'([^'\\]|\\.)*$/, "string.invalid"],
        [/(?:[fFrRbBuU]{1,2})?"/, "string", "@dqs"],
        [/(?:[fFrRbBuU]{1,2})?'/, "string", "@sqs"],
        // comments
        [/#.*$/, "comment"],
        // identifiers and keywords
        [
          /[a-zA-Z_]\w*/,
          {
            cases: {
              "@keywords": "keyword",
              "@builtins": "type.identifier",
              "@default": "identifier",
            },
          },
        ],
        // numbers
        [/0[xX][0-9a-fA-F](_?[0-9a-fA-F])*/, "number.hex"],
        [/0[oO][0-7](_?[0-7])*/, "number.octal"],
        [/0[bB][01](_?[01])*/, "number.binary"],
        [/\d[\d_]*(\.\d[\d_]*)?([eE][+-]?\d[\d_]*)?[jJ]?/, "number"],
        // operators
        [/[+\-*/%&|^~<>!=]=?/, "operator"],
        [/[{}()[\]]/, "@brackets"],
        [/[;,.]/, "delimiter"],
      ],
      // triple-double-quoted string
      tdqs: [
        [/[^"\\]+/, "string"],
        [/\\./, "string.escape"],
        [/"""/, "string", "@pop"],
        [/"/, "string"],
      ],
      // triple-single-quoted string
      tsqs: [
        [/[^'\\]+/, "string"],
        [/\\./, "string.escape"],
        [/'''/, "string", "@pop"],
        [/'/, "string"],
      ],
      // double-quoted string
      dqs: [
        [/[^"\\]+/, "string"],
        [/\\./, "string.escape"],
        [/"/, "string", "@pop"],
      ],
      // single-quoted string
      sqs: [
        [/[^'\\]+/, "string"],
        [/\\./, "string.escape"],
        [/'/, "string", "@pop"],
      ],
    },
  })
}

export const defineMonacoThemes: BeforeMount = (monaco) => {
  defineDiffLanguage(monaco)
  fixPythonTripleQuotes(monaco)

  monaco.editor.defineTheme(MONACO_LIGHT_THEME, {
    base: "vs",
    inherit: true,
    rules: monacoTokenRules.light,
    colors: monacoThemeColors.light,
  })

  monaco.editor.defineTheme(MONACO_DARK_THEME, {
    base: "vs-dark",
    inherit: true,
    rules: monacoTokenRules.dark,
    colors: monacoThemeColors.dark,
  })
}

export function useMonacoThemeSync() {
  const [theme, setTheme] = useState(MONACO_LIGHT_THEME)

  useEffect(() => {
    if (typeof window === "undefined") return
    const root = document.documentElement

    const syncTheme = () => {
      setTheme(
        root.classList.contains("dark") ? MONACO_DARK_THEME : MONACO_LIGHT_THEME
      )
    }

    syncTheme()

    const observer = new MutationObserver(syncTheme)
    observer.observe(root, {
      attributes: true,
      attributeFilter: ["class"],
    })
    return () => {
      observer.disconnect()
    }
  }, [])

  return theme
}
