import { describe, it, expect } from 'vitest';
import { EditorState } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { forEachDiagnostic } from '@codemirror/lint';
import { mustacheLinter } from './mustache-linter';
import { availableVariables } from './alert-variables';

function makeView(doc: string) {
  return new EditorView({
    state: EditorState.create({
      doc,
      extensions: [mustacheLinter(availableVariables('ROUTE_METRIC'))],
    }),
  });
}

async function diagnosticsFor(doc: string): Promise<
  Array<{ severity: string; message: string; from: number; to: number }>
> {
  const view = makeView(doc);
  // @codemirror/lint debounces with a default 750ms delay — wait past that for the source to run.
  await new Promise((r) => setTimeout(r, 900));
  const out: Array<{ severity: string; message: string; from: number; to: number }> = [];
  forEachDiagnostic(view.state, (d, from, to) =>
    out.push({ severity: d.severity, message: d.message, from, to }),
  );
  view.destroy();
  return out;
}

describe('mustacheLinter', () => {
  it('accepts a valid template with no warnings', async () => {
    const diags = await diagnosticsFor('Rule {{rule.name}} in env {{env.slug}}');
    expect(diags).toEqual([]);
  });

  it('flags unclosed {{', async () => {
    const diags = await diagnosticsFor('Hello {{alert.firedAt');
    expect(diags.find((d) => d.severity === 'error' && /unclosed/i.test(d.message))).toBeTruthy();
  });

  it('warns on unknown variable', async () => {
    const diags = await diagnosticsFor('{{exchange.id}}');
    const warn = diags.find((d) => d.severity === 'warning');
    expect(warn?.message).toMatch(/exchange\.id.*not available/);
  });
});
