let configured = false;

const coreCmdlets = [
  'Add-Content', 'Clear-Content', 'Clear-Item', 'Compare-Object', 'ConvertFrom-Json', 'ConvertTo-Json',
  'Copy-Item', 'ForEach-Object', 'Format-List', 'Format-Table', 'Get-ChildItem', 'Get-Command',
  'Get-Content', 'Get-Date', 'Get-Help', 'Get-Item', 'Get-Module', 'Get-Process', 'Get-Service',
  'Get-Variable', 'Import-Module', 'Invoke-Command', 'Join-Path', 'Measure-Object', 'Move-Item',
  'New-Item', 'New-Object', 'New-PSSession', 'Out-File', 'Read-Host', 'Receive-Job', 'Remove-Item',
  'Remove-PSSession', 'Resolve-Path', 'Restart-Service', 'Select-Object', 'Set-Content', 'Set-Item',
  'Set-StrictMode', 'Sort-Object', 'Start-Job', 'Start-Process', 'Start-Service', 'Stop-Job',
  'Stop-Process', 'Stop-Service', 'Test-Path', 'Wait-Job', 'Where-Object', 'Write-Error',
  'Write-Host', 'Write-Output', 'Write-Verbose', 'Write-Warning'
];

const psPatterns = [
  { label: 'function block', insertText: 'function ${1:Name} {\n    param(\n        ${2:[string]$Value}\n    )\n\n    ${0}\n}', detail: 'PowerShell function snippet' },
  { label: 'try/catch', insertText: 'try {\n    ${1}\n}\ncatch {\n    Write-Error $_\n    ${0}\n}', detail: 'PowerShell error handling snippet' },
  { label: 'foreach', insertText: 'foreach ($${1:item} in $${2:items}) {\n    ${0}\n}', detail: 'PowerShell foreach loop' },
  { label: 'if/else', insertText: 'if (${1:$condition}) {\n    ${2}\n}\nelse {\n    ${0}\n}', detail: 'PowerShell conditional' },
  { label: 'param block', insertText: 'param(\n    [Parameter(Mandatory = $${1:false})]\n    [${2:string}]$${3:Name}\n)\n\n${0}', detail: 'PowerShell param block' }
];

export function configurePowerShellMonaco(monaco, getContext = () => ({})) {
  if (!configured) {
    configured = true;
    monaco.languages.register({ id: 'powershell', extensions: ['.ps1', '.psm1', '.psd1'], aliases: ['PowerShell', 'powershell'] });
    monaco.languages.setLanguageConfiguration('powershell', languageConfiguration);
    monaco.languages.setMonarchTokensProvider('powershell', tokensProvider);
    monaco.editor.defineTheme('posh-vscode-dark', vscodeTheme);
  }

  monaco.languages.registerCompletionItemProvider('powershell', {
    triggerCharacters: ['-', '$', '{', '.', ':'],
    provideCompletionItems(model, position) {
      const range = completionRange(model, position);
      return { suggestions: buildSuggestions(monaco, getContext(), range) };
    }
  });

  monaco.languages.registerHoverProvider('powershell', {
    provideHover(model, position) {
      const word = model.getWordAtPosition(position)?.word;
      if (!word) return null;
      const context = getContext();
      const fn = (context.psadtCatalog?.functions || []).find((item) => item.name === word);
      if (fn) {
        return {
          contents: [
            { value: `**${fn.name}**` },
            { value: `PSADT ${fn.category || 'function'} command.` }
          ]
        };
      }
      const variable = allVariables(context.variableCatalog).find((item) => item.name === word || item.syntax === `$${word}`);
      if (variable) {
        return {
          contents: [
            { value: `**$${variable.name}**` },
            { value: variable.description || `${variable.category || 'Variable'} value.` }
          ]
        };
      }
      return null;
    }
  });
}

function completionRange(model, position) {
  const line = model.getLineContent(position.lineNumber).slice(0, position.column - 1);
  const match = line.match(/(?:\{\{[A-Za-z0-9_:.-]*|\$?[A-Za-z_][\w:.-]*|[A-Za-z]+-[A-Za-z0-9-]*)$/);
  const length = match?.[0]?.length || 0;
  return {
    startLineNumber: position.lineNumber,
    endLineNumber: position.lineNumber,
    startColumn: Math.max(1, position.column - length),
    endColumn: position.column
  };
}

function buildSuggestions(monaco, context, range) {
  const kinds = monaco.languages.CompletionItemKind;
  const inserts = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
  const suggestions = [];

  for (const cmdlet of coreCmdlets) {
    suggestions.push({
      label: cmdlet,
      kind: kinds.Function,
      insertText: `${cmdlet} `,
      detail: 'PowerShell cmdlet',
      range
    });
  }

  for (const pattern of psPatterns) {
    suggestions.push({
      label: pattern.label,
      kind: kinds.Snippet,
      insertText: pattern.insertText,
      insertTextRules: inserts,
      detail: pattern.detail,
      range
    });
  }

  for (const fn of context.psadtCatalog?.functions || []) {
    suggestions.push({
      label: fn.name,
      kind: kinds.Method,
      insertText: fn.snippet || `${fn.name} `,
      detail: `PSADT ${fn.category || 'function'}`,
      documentation: `PSAppDeployToolkit command${fn.category ? ` in ${fn.category}` : ''}.`,
      range
    });
  }

  for (const snippet of context.psadtCatalog?.snippets || []) {
    suggestions.push({
      label: `psadt: ${snippet.title}`,
      kind: kinds.Snippet,
      insertText: snippet.body,
      detail: `PSADT snippet - ${snippet.category}`,
      documentation: snippet.functionName || snippet.category,
      range
    });
  }

  for (const variable of allVariables(context.variableCatalog)) {
    suggestions.push({
      label: variable.syntax || `$${variable.name}`,
      kind: variable.sensitive ? kinds.Value : kinds.Variable,
      insertText: variable.syntax || `$${variable.name}`,
      detail: variable.category || variable.source || 'Variable',
      documentation: variable.description || '',
      range
    });
    suggestions.push({
      label: variable.token || `{{${variable.name}}}`,
      kind: kinds.Reference,
      insertText: variable.token || `{{${variable.name}}}`,
      detail: 'POSHManager token',
      documentation: variable.description || '',
      range
    });
  }

  for (const asset of context.assets || []) {
    suggestions.push({
      label: asset.referenceToken,
      kind: kinds.File,
      insertText: asset.referenceToken,
      detail: `Asset - ${asset.kind || 'file'}`,
      documentation: asset.packagePath || asset.name,
      range
    });
  }

  return suggestions;
}

function allVariables(catalog = {}) {
  return [
    ...(catalog.builtIns || []),
    ...(catalog.psadt || []),
    ...(catalog.custom || [])
  ];
}

const languageConfiguration = {
  comments: {
    lineComment: '#',
    blockComment: ['<#', '#>']
  },
  brackets: [['{', '}'], ['[', ']'], ['(', ')']],
  autoClosingPairs: [
    { open: '{', close: '}' },
    { open: '[', close: ']' },
    { open: '(', close: ')' },
    { open: '"', close: '"', notIn: ['string'] },
    { open: "'", close: "'", notIn: ['string', 'comment'] }
  ],
  surroundingPairs: [
    { open: '{', close: '}' },
    { open: '[', close: ']' },
    { open: '(', close: ')' },
    { open: '"', close: '"' },
    { open: "'", close: "'" }
  ],
  folding: {
    markers: {
      start: /^#region\b/,
      end: /^#endregion\b/
    }
  }
};

const tokensProvider = {
  ignoreCase: true,
  tokenizer: {
    root: [
      [/<#/, 'comment', '@comment'],
      [/#.*$/, 'comment'],
      [/\$\{?[A-Za-z_][\w:]*\}?/, 'variable'],
      [/\{\{[^}]+\}\}/, 'variable.predefined'],
      [/\b(function|param|process|begin|end|dynamicparam|class|enum|if|elseif|else|switch|foreach|for|while|do|until|try|catch|finally|throw|return|break|continue|trap|using|workflow|configuration|data)\b/, 'keyword'],
      [/\b(true|false|null)\b/, 'constant'],
      [/\b[A-Za-z]+-[A-Za-z][\w-]*\b/, 'support.function'],
      [/-[A-Za-z][\w-]*/, 'attribute.name'],
      [/\[[A-Za-z0-9_.`]+\]/, 'type'],
      [/"([^"\\]|\\.)*$/, 'string.invalid'],
      [/"/, 'string', '@stringDouble'],
      [/'/, 'string', '@stringSingle'],
      [/\d+(\.\d+)?/, 'number'],
      [/[{}()[\]]/, '@brackets'],
      [/[|=+\-*/%!<>~?&]+/, 'operator']
    ],
    comment: [
      [/[^<#]+/, 'comment'],
      [/#>/, 'comment', '@pop'],
      [/[<#]/, 'comment']
    ],
    stringDouble: [
      [/[^"$`]+/, 'string'],
      [/`./, 'string.escape'],
      [/\$\{?[A-Za-z_][\w:]*\}?/, 'variable'],
      [/"/, 'string', '@pop']
    ],
    stringSingle: [
      [/[^']+/, 'string'],
      [/'/, 'string', '@pop']
    ]
  }
};

const vscodeTheme = {
  base: 'vs-dark',
  inherit: true,
  rules: [
    { token: '', foreground: 'd4d4d4', background: '1e1e1e' },
    { token: 'comment', foreground: '6a9955', fontStyle: 'italic' },
    { token: 'keyword', foreground: 'c586c0' },
    { token: 'constant', foreground: '569cd6' },
    { token: 'string', foreground: 'ce9178' },
    { token: 'string.escape', foreground: 'd7ba7d' },
    { token: 'number', foreground: 'b5cea8' },
    { token: 'type', foreground: '4ec9b0' },
    { token: 'variable', foreground: '9cdcfe' },
    { token: 'variable.predefined', foreground: 'dcdcaa' },
    { token: 'support.function', foreground: 'dcdcaa' },
    { token: 'attribute.name', foreground: '9cdcfe' },
    { token: 'operator', foreground: 'd4d4d4' }
  ],
  colors: {
    'editor.background': '#1e1e1e',
    'editor.foreground': '#d4d4d4',
    'editorGutter.background': '#1e1e1e',
    'editorLineNumber.foreground': '#858585',
    'editorLineNumber.activeForeground': '#c6c6c6',
    'editorCursor.foreground': '#aeafad',
    'editor.selectionBackground': '#264f78',
    'editor.inactiveSelectionBackground': '#3a3d41',
    'editor.lineHighlightBackground': '#2a2d2e',
    'editor.lineHighlightBorder': '#00000000',
    'editorIndentGuide.background1': '#404040',
    'editorIndentGuide.activeBackground1': '#707070',
    'editorWhitespace.foreground': '#404040',
    'editorWidget.background': '#252526',
    'editorWidget.border': '#454545',
    'editorSuggestWidget.background': '#252526',
    'editorSuggestWidget.border': '#454545',
    'editorSuggestWidget.foreground': '#d4d4d4',
    'editorSuggestWidget.highlightForeground': '#18a3ff',
    'editorSuggestWidget.selectedBackground': '#04395e',
    'editorHoverWidget.background': '#252526',
    'editorHoverWidget.border': '#454545',
    'scrollbarSlider.background': '#79797966',
    'scrollbarSlider.hoverBackground': '#646464b3',
    'scrollbarSlider.activeBackground': '#bfbfbf66',
    'minimap.background': '#1e1e1e'
  }
};
