import type { Monaco } from '@monaco-editor/react';

let registered = false;

export function registerMonacoCompletions(monaco: Monaco) {
  if (registered) return;
  registered = true;

  // Completion items for Python
  monaco.languages.registerCompletionItemProvider('python', {
    triggerCharacters: ['.'],
    provideCompletionItems: (model, position) => {
      const lineUntilPosition = model.getValueInRange({
        startLineNumber: position.lineNumber,
        startColumn: 1,
        endLineNumber: position.lineNumber,
        endColumn: position.column,
      });

      const word = model.getWordUntilPosition(position);
      const range = {
        startLineNumber: position.lineNumber,
        endLineNumber: position.lineNumber,
        startColumn: word.startColumn,
        endColumn: word.endColumn,
      };

      const suggestions = [
        {
          label: 'print',
          kind: monaco.languages.CompletionItemKind.Function,
          insertText: 'print(${1:value})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Prints specified objects to standard output.',
          range,
        },
        {
          label: 'len',
          kind: monaco.languages.CompletionItemKind.Function,
          insertText: 'len(${1:obj})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Returns the number of items in a container.',
          range,
        },
        {
          label: 'range',
          kind: monaco.languages.CompletionItemKind.Function,
          insertText: 'range(${1:stop})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Generates a sequence of numbers.',
          range,
        },
        {
          label: 'enumerate',
          kind: monaco.languages.CompletionItemKind.Function,
          insertText: 'enumerate(${1:iterable})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Yields index and value tuples from an iterable.',
          range,
        },
        {
          label: 'append',
          kind: monaco.languages.CompletionItemKind.Method,
          insertText: 'append(${1:item})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Appends a new item to the end of the list.',
          range,
        },
        {
          label: 'split',
          kind: monaco.languages.CompletionItemKind.Method,
          insertText: 'split(${1:sep})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Splits string into a list of substrings.',
          range,
        },
        {
          label: 'def',
          kind: monaco.languages.CompletionItemKind.Keyword,
          insertText: 'def ${1:function_name}(${2:params}):\n    ${3:pass}',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Defines a Python function.',
          range,
        },
      ];

      return { suggestions };
    },
  });

  // Completion items for JavaScript / TypeScript
  ['javascript', 'typescript'].forEach((lang) => {
    monaco.languages.registerCompletionItemProvider(lang, {
      triggerCharacters: ['.'],
      provideCompletionItems: (model, position) => {
        const lineUntilPosition = model.getValueInRange({
          startLineNumber: position.lineNumber,
          startColumn: 1,
          endLineNumber: position.lineNumber,
          endColumn: position.column,
        });

        const word = model.getWordUntilPosition(position);
        const range = {
          startLineNumber: position.lineNumber,
          endLineNumber: position.lineNumber,
          startColumn: word.startColumn,
          endColumn: word.endColumn,
        };

        if (lineUntilPosition.endsWith('console.')) {
          return {
            suggestions: [
              {
                label: 'log',
                kind: monaco.languages.CompletionItemKind.Method,
                insertText: 'log(${1:message});',
                insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                documentation: 'Outputs a message to the debugging console.',
                range,
              },
              {
                label: 'error',
                kind: monaco.languages.CompletionItemKind.Method,
                insertText: 'error(${1:err});',
                insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                documentation: 'Outputs an error message to the console.',
                range,
              },
              {
                label: 'warn',
                kind: monaco.languages.CompletionItemKind.Method,
                insertText: 'warn(${1:msg});',
                insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
                documentation: 'Outputs a warning message to the console.',
                range,
              },
            ],
          };
        }

        const suggestions = [
          {
            label: 'console.log',
            kind: monaco.languages.CompletionItemKind.Snippet,
            insertText: 'console.log(${1:val});',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            documentation: 'Print debug message to console.',
            range,
          },
          {
            label: 'map',
            kind: monaco.languages.CompletionItemKind.Method,
            insertText: 'map((${1:item}) => ${2:item})',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            documentation: 'Array map transformation function.',
            range,
          },
          {
            label: 'filter',
            kind: monaco.languages.CompletionItemKind.Method,
            insertText: 'filter((${1:item}) => ${2:true})',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            documentation: 'Array filter function.',
            range,
          },
        ];

        return { suggestions };
      },
    });
  });

  // Completion items for Rust
  monaco.languages.registerCompletionItemProvider('rust', {
    triggerCharacters: ['.', ':'],
    provideCompletionItems: (model, position) => {
      const word = model.getWordUntilPosition(position);
      const range = {
        startLineNumber: position.lineNumber,
        endLineNumber: position.lineNumber,
        startColumn: word.startColumn,
        endColumn: word.endColumn,
      };

      const suggestions = [
        {
          label: 'println!',
          kind: monaco.languages.CompletionItemKind.Function,
          insertText: 'println!("${1:{}}", ${2:val});',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Prints formatted text to stdout.',
          range,
        },
        {
          label: 'format!',
          kind: monaco.languages.CompletionItemKind.Function,
          insertText: 'format!("${1:{}}", ${2:val})',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Constructs a formatted String.',
          range,
        },
        {
          label: 'Vec::push',
          kind: monaco.languages.CompletionItemKind.Method,
          insertText: 'push(${1:val});',
          insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
          documentation: 'Appends element to back of vector.',
          range,
        },
      ];

      return { suggestions };
    },
  });

  // Completion items for Go
  monaco.languages.registerCompletionItemProvider('go', {
    triggerCharacters: ['.'],
    provideCompletionItems: (model, position) => {
      const lineUntilPosition = model.getValueInRange({
        startLineNumber: position.lineNumber,
        startColumn: 1,
        endLineNumber: position.lineNumber,
        endColumn: position.column,
      });

      const word = model.getWordUntilPosition(position);
      const range = {
        startLineNumber: position.lineNumber,
        endLineNumber: position.lineNumber,
        startColumn: word.startColumn,
        endColumn: word.endColumn,
      };

      if (lineUntilPosition.endsWith('fmt.')) {
        return {
          suggestions: [
            {
              label: 'Println',
              kind: monaco.languages.CompletionItemKind.Function,
              insertText: 'Println(${1:v})',
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
              documentation: 'Formats using default formats and writes to standard output.',
              range,
            },
            {
              label: 'Printf',
              kind: monaco.languages.CompletionItemKind.Function,
              insertText: 'Printf("${1:%v}\\n", ${2:v})',
              insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
              documentation: 'Formats according to specifier and writes to standard output.',
              range,
            },
          ],
        };
      }

      return {
        suggestions: [
          {
            label: 'fmt.Println',
            kind: monaco.languages.CompletionItemKind.Snippet,
            insertText: 'fmt.Println(${1:v})',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            documentation: 'Print line to stdout.',
            range,
          },
          {
            label: 'make',
            kind: monaco.languages.CompletionItemKind.Function,
            insertText: 'make(${1:type}, ${2:len})',
            insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
            documentation: 'Allocates slice, map, or channel.',
            range,
          },
        ],
      };
    },
  });
}
