export const SPOON_DARK = 'spoon-dark';
export const SPOON_LIGHT = 'spoon-light';

type ThemeRule = { token: string; foreground?: string; fontStyle?: string };
type ThemeData = {
  base: 'vs' | 'vs-dark';
  inherit: boolean;
  rules: ThemeRule[];
  colors: Record<string, string>;
};
type DiagnosticsDefaults = {
  setDiagnosticsOptions: (options: {
    noSemanticValidation?: boolean;
    noSyntaxValidation?: boolean;
    noSuggestionDiagnostics?: boolean;
  }) => void;
};

// Minimal typed surface of the bits of the Monaco namespace we touch. Avoids
// depending on monaco-editor's full (and, under our eslint program, unresolved)
// type graph while keeping these calls fully type-checked.
export type MonacoLike = {
  editor: {
    defineTheme: (name: string, data: ThemeData) => void;
    remeasureFonts: () => void;
  };
  languages: {
    typescript: {
      typescriptDefaults: DiagnosticsDefaults;
      javascriptDefaults: DiagnosticsDefaults;
    };
  };
};

// Hex equivalents of the site's oklch design tokens (tools/tailwind/theme.css),
// so the editor matches the rest of the app. Brand accent is the teal --primary.
const dark = {
  bg: '#080e14', // --background
  surface: '#10171e', // --card
  surfaceAlt: '#192028', // --muted
  border: '#29313a', // --border
  fg: '#eef3f5', // --foreground
  fgDim: '#cdd6dc',
  muted: '#93a1a9', // --muted-foreground
  comment: '#6b7d88',
  teal: '#1fb895', // --primary
  mint: '#8fd6b4',
  cyan: '#5fd0e0',
  blue: '#6aa6ff',
  amber: '#e3b341',
  red: '#f3625d', // --destructive
};

const light = {
  bg: '#f7fbfa', // --background
  surface: '#ffffff', // --card
  surfaceAlt: '#eaeff3', // --muted
  border: '#d4dce2', // --border
  fg: '#0d1218', // --foreground
  fgDim: '#26323c',
  muted: '#555f68', // --muted-foreground
  comment: '#6b7680',
  teal: '#007560', // --primary
  mint: '#2f8f6e',
  cyan: '#0f7d92',
  blue: '#2f6bd8',
  amber: '#9a6b00',
  red: '#d73337', // --destructive
};

const hex = (value: string) => value.slice(1);

const themeData = (p: typeof dark, base: 'vs' | 'vs-dark'): ThemeData => ({
  base,
  inherit: true,
  rules: [
    { token: '', foreground: hex(p.fg) },
    { token: 'comment', foreground: hex(p.comment), fontStyle: 'italic' },
    { token: 'keyword', foreground: hex(p.teal) },
    { token: 'keyword.control', foreground: hex(p.teal) },
    { token: 'storage', foreground: hex(p.teal) },
    { token: 'string', foreground: hex(p.mint) },
    { token: 'string.key.json', foreground: hex(p.cyan) },
    { token: 'string.value.json', foreground: hex(p.mint) },
    { token: 'number', foreground: hex(p.amber) },
    { token: 'constant', foreground: hex(p.amber) },
    { token: 'regexp', foreground: hex(p.amber) },
    { token: 'type', foreground: hex(p.cyan) },
    { token: 'type.identifier', foreground: hex(p.cyan) },
    { token: 'interface', foreground: hex(p.cyan) },
    { token: 'namespace', foreground: hex(p.cyan) },
    { token: 'function', foreground: hex(p.blue) },
    { token: 'variable', foreground: hex(p.fgDim) },
    { token: 'variable.parameter', foreground: hex(p.fgDim) },
    { token: 'property', foreground: hex(p.fgDim) },
    { token: 'operator', foreground: hex(p.muted) },
    { token: 'delimiter', foreground: hex(p.muted) },
    { token: 'tag', foreground: hex(p.teal) },
    { token: 'attribute.name', foreground: hex(p.amber) },
    { token: 'attribute.value', foreground: hex(p.mint) },
    { token: 'metatag', foreground: hex(p.teal) },
  ],
  colors: {
    'editor.background': p.bg,
    'editor.foreground': p.fg,
    'editorCursor.foreground': p.teal,
    'editorLineNumber.foreground': p.border,
    'editorLineNumber.activeForeground': p.muted,
    'editor.lineHighlightBackground': p.surface,
    'editor.selectionBackground': `${p.teal}33`,
    'editor.inactiveSelectionBackground': `${p.teal}22`,
    'editor.findMatchBackground': `${p.teal}55`,
    'editor.findMatchHighlightBackground': `${p.teal}33`,
    'editorWhitespace.foreground': p.border,
    'editorIndentGuide.background1': p.surfaceAlt,
    'editorIndentGuide.activeBackground1': p.border,
    'editorGutter.background': p.bg,
    'editorWidget.background': p.surface,
    'editorWidget.border': p.border,
    'editorHoverWidget.background': p.surface,
    'editorHoverWidget.border': p.border,
    'editorSuggestWidget.background': p.surface,
    'editorSuggestWidget.border': p.border,
    'editorSuggestWidget.selectedBackground': p.surfaceAlt,
    'editorBracketMatch.background': `${p.teal}22`,
    'editorBracketMatch.border': p.teal,
    'editorError.foreground': p.red,
    'scrollbarSlider.background': `${p.border}aa`,
    'scrollbarSlider.hoverBackground': p.border,
    'scrollbarSlider.activeBackground': p.muted,
  },
});

let configured = false;

/**
 * Defines the site-matched editor themes and quiets the in-browser TypeScript
 * service. Monaco's TS worker has no access to the project's node_modules or the
 * `~`/`@` path aliases, so its semantic diagnostics (e.g. "Cannot find module
 * '~/server/auth'") are always false positives here. We keep real syntax errors
 * and disable the unresolvable semantic noise. Runs once per page load.
 */
export const configureSpoonMonaco = (monaco: MonacoLike) => {
  monaco.editor.defineTheme(SPOON_DARK, themeData(dark, 'vs-dark'));
  monaco.editor.defineTheme(SPOON_LIGHT, themeData(light, 'vs'));
  if (configured) return;
  configured = true;
  for (const defaults of [
    monaco.languages.typescript.typescriptDefaults,
    monaco.languages.typescript.javascriptDefaults,
  ]) {
    defaults.setDiagnosticsOptions({
      noSemanticValidation: true,
      noSuggestionDiagnostics: true,
      noSyntaxValidation: false,
    });
  }
};

/** Re-measures glyph widths once the web font finishes loading so they align. */
export const remeasureFontsWhenReady = (monaco: MonacoLike) => {
  void document.fonts.ready.then(() => monaco.editor.remeasureFonts());
};
