import type { CompletionContext, CompletionResult, Completion } from '@codemirror/autocomplete';
import type { AlertVariable } from './alert-variables';

/** Build a CodeMirror completion source that triggers after `{{` (with optional whitespace)
 *  and suggests variable paths from the given list. */
export function mustacheCompletionSource(variables: readonly AlertVariable[]) {
  return (context: CompletionContext): CompletionResult | null => {
    // Look backward for `{{` optionally followed by whitespace, then an in-progress identifier.
    const line = context.state.doc.lineAt(context.pos);
    const textBefore = line.text.slice(0, context.pos - line.from);
    const m = /\{\{\s*([a-zA-Z0-9_.]*)$/.exec(textBefore);
    if (!m) return null;

    const partial = m[1];
    const from = context.pos - partial.length;

    const options: Completion[] = variables
      .filter((v) => v.path.startsWith(partial))
      .map((v) => ({
        label: v.path,
        type: v.mayBeNull ? 'variable' : 'constant',
        detail: v.type,
        info: v.mayBeNull
          ? `${v.description} (may be null) · e.g. ${v.sampleValue}`
          : `${v.description} · e.g. ${v.sampleValue}`,
        // Inserting closes the Mustache tag; CM will remove the partial prefix.
        // closeBrackets auto-inserts `}}` after the user types `{{`, so the
        // cursor is usually already sitting before a `}}`. Consume it when
        // present so we don't end up with `{{path}}}}`.
        apply: (view, _completion, completionFrom, to) => {
          const docLen = view.state.doc.length;
          const afterTo = view.state.doc.sliceString(to, Math.min(to + 2, docLen));
          const consumeExisting = afterTo === '}}' ? 2 : 0;
          const insert = `${v.path}}}`;
          view.dispatch({
            changes: { from: completionFrom, to: to + consumeExisting, insert },
            selection: { anchor: completionFrom + insert.length },
          });
        },
      }));

    return {
      from,
      to: context.pos,
      options,
      validFor: /^[a-zA-Z0-9_.]*$/,
    };
  };
}
