import type { Completion, CompletionContext, CompletionSource } from '@codemirror/autocomplete';

import type { FormulaFunction, ParameterSlot } from '#/api/x/eln/formulas';

import { StreamLanguage } from '@codemirror/language';

export type FormulaResourceKind = 'all' | 'function' | 'parameter';

const PARAMETER_SECTION = { name: '参数', rank: 1 } as const;
const FUNCTION_SECTION = { name: '函数', rank: 2 } as const;
const PARAMETER_TYPE_LABELS: Record<string, string> = {
  BOOLEAN: '布尔值',
  DECIMAL: '数值',
  DECIMAL_LIST: '数值集合',
  TEXT: '文本',
};

export const formulaLanguage = StreamLanguage.define({
  startState: () => ({}),
  token(stream) {
    if (stream.eatSpace()) return null;
    /* eslint-disable unicorn/prefer-regexp-test -- StringStream.match advances the CodeMirror tokenizer */
    if (stream.match(/\$\{[^}]*\}/)) return 'variableName';
    if (stream.match(/'(?:\\.|[^'\\\r\n])*'|"(?:\\.|[^"\\\r\n])*"/)) return 'string';
    if (stream.match(/[A-Z_]\w*/i)) return 'variableName';
    if (stream.match(/\d+(?:\.\d*)?|\.\d+/)) return 'number';
    if (stream.match(/&&|\|\||[!<>=]=?|[()+\-*/^,%]/)) return 'operator';
    /* eslint-enable unicorn/prefer-regexp-test */
    stream.next();
    return null;
  },
});

export function createFormulaCompletions(parameters: ParameterSlot[], functions: FormulaFunction[], kind: FormulaResourceKind = 'all'): Completion[] {
  const parameterItems: Completion[] = parameters.map((parameter) => ({
    apply: parameter.canshuBianma,
    detail: [parameter.canshuBianma, PARAMETER_TYPE_LABELS[parameter.shujuLeixing], parameter.danwei].filter(Boolean).join(' · '),
    displayLabel: parameter.canshuMingcheng,
    label: `${parameter.canshuMingcheng} ${parameter.canshuBianma}`,
    section: PARAMETER_SECTION,
    type: 'variable',
  }));
  const functionItems: Completion[] = functions.map((formula) => ({
    apply: `${formula.code}(`,
    detail: formula.signature,
    displayLabel: formula.chineseName,
    info: [formula.description, formula.example && `示例：${formula.example}`].filter(Boolean).join('\n'),
    label: `${formula.chineseName} ${formula.code}`,
    section: FUNCTION_SECTION,
    type: 'function',
  }));
  if (kind === 'parameter') return parameterItems;
  if (kind === 'function') return functionItems;
  return [...parameterItems, ...functionItems];
}

export function formulaCompletionSource(
  parameters: ParameterSlot[],
  functions: FormulaFunction[],
  kind: (() => FormulaResourceKind) | FormulaResourceKind = 'all',
): CompletionSource {
  return (context: CompletionContext) => {
    const word = context.matchBefore(/[\w\u3400-\u9FFF]+/);
    if (!word && !context.explicit) return null;
    const activeKind = typeof kind === 'function' ? kind() : kind;
    return { from: word ? word.from : context.pos, options: createFormulaCompletions(parameters, functions, activeKind) };
  };
}

export function insertFormulaText(value: string, from: number, to: number, text: string): string {
  return `${value.slice(0, from)}${text}${value.slice(to)}`;
}
