import {
  htmlDiagnostics,
  cssDiagnostics,
  jsDiagnostics,
} from './bms-input-code.linters';

describe('htmlDiagnostics', () => {
  it('retourne aucun diagnostic sur une chaîne vide', () => {
    expect(htmlDiagnostics('')).toHaveLength(0);
  });

  it('retourne aucun diagnostic sur du HTML bien formé', () => {
    expect(htmlDiagnostics('<div><p>Hello</p></div>')).toHaveLength(0);
  });

  it('retourne aucun diagnostic avec un placeholder XHTML self-closing', () => {
    expect(
      htmlDiagnostics('<div><placeholder id="position_1" /></div>'),
    ).toHaveLength(0);
  });

  it('retourne aucun diagnostic sur les balises void HTML5 sans auto-fermeture', () => {
    expect(htmlDiagnostics('<br>')).toHaveLength(0);
    expect(htmlDiagnostics('<img src="a.png" alt="">')).toHaveLength(0);
    expect(htmlDiagnostics('<meta charset="utf-8">')).toHaveLength(0);
    expect(htmlDiagnostics('<link rel="stylesheet" href="a.css">')).toHaveLength(0);
    expect(htmlDiagnostics('<input type="text">')).toHaveLength(0);
  });

  it('retourne aucun diagnostic sur les balises void HTML5 déjà auto-fermantes', () => {
    expect(htmlDiagnostics('<br/>')).toHaveLength(0);
    expect(htmlDiagnostics('<meta charset="utf-8"/>')).toHaveLength(0);
  });

  it('retourne aucun diagnostic pour un attribut booléen sans valeur', () => {
    expect(htmlDiagnostics('<div hidden><p>Hello</p></div>')).toHaveLength(0);
    expect(htmlDiagnostics('<input type="checkbox" checked>')).toHaveLength(0);
    expect(htmlDiagnostics('<body data-ofos><p>Hello</p></body>')).toHaveLength(0);
  });

  it('retourne aucun diagnostic sur un template HTML5 réaliste avec attributs booléens', () => {
    const html = `<html lang="fr">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width">
        <link rel="stylesheet" href="style.css">
    </head>
    <body data-ofos>
        <placeholder/>
    </body>
</html>`;
    expect(htmlDiagnostics(html)).toHaveLength(0);
  });

  it('retourne une erreur sur une balise non fermée', () => {
    const diags = htmlDiagnostics('<div><p>Hello</div>');
    expect(diags).toHaveLength(1);
    expect(diags[0].severity).toBe('error');
    expect(diags[0].message).toContain('HTML invalide');
  });

  it('retourne une erreur sur un attribut mal formé', () => {
    const diags = htmlDiagnostics('<div class=>test</div>');
    expect(diags).toHaveLength(1);
    expect(diags[0].severity).toBe('error');
  });

  it("positionne le diagnostic à proximité de l'erreur", () => {
    // <div><p>Hello</div> — l'erreur est sur le </div> qui ferme mal le <p>
    const code = '<div><p>Hello</div>';
    const diags = htmlDiagnostics(code);
    expect(diags[0].from).toBeGreaterThanOrEqual(0);
    expect(diags[0].to).toBeGreaterThan(diags[0].from);
    // le diagnostic doit pointer dans le contenu, pas sur l'intégralité
    expect(diags[0].to).toBeLessThanOrEqual(code.length);
  });

  it('positionne le diagnostic sur la ligne correcte pour une erreur multi-lignes', () => {
    const code = '<div>\n  <p>Hello\n</div>';
    const diags = htmlDiagnostics(code);
    expect(diags).toHaveLength(1);
    // l'erreur est après le début du document
    expect(diags[0].from).toBeGreaterThanOrEqual(0);
  });
});

describe('cssDiagnostics', () => {
  it('retourne aucun diagnostic sur une chaîne vide', () => {
    expect(cssDiagnostics('')).toHaveLength(0);
  });

  it('retourne aucun diagnostic si CSSStyleSheet.replaceSync est indisponible (jsdom)', () => {
    // jsdom ne supporte pas replaceSync — le linter est silencieux dans cet environnement
    expect(cssDiagnostics('.foo { color: red; }')).toHaveLength(0);
  });
});

describe('jsDiagnostics', () => {
  it('retourne aucun diagnostic sur une chaîne vide', () => {
    expect(jsDiagnostics('')).toHaveLength(0);
  });

  it('retourne aucun diagnostic sur du JS syntaxiquement valide', () => {
    expect(jsDiagnostics('const x = 1; console.log(x);')).toHaveLength(0);
  });

  it('retourne aucun diagnostic sur une fonction valide', () => {
    expect(jsDiagnostics('function foo(a, b) { return a + b; }')).toHaveLength(
      0,
    );
  });

  it('retourne une erreur sur une accolade mal formée', () => {
    const diags = jsDiagnostics('const x = {;');
    expect(diags).toHaveLength(1);
    expect(diags[0].severity).toBe('error');
    expect(diags[0].message).toContain('JavaScript invalide');
  });

  it('retourne une erreur sur un bloc de fonction non fermé', () => {
    const diags = jsDiagnostics('function foo() {');
    expect(diags).toHaveLength(1);
    expect(diags[0].severity).toBe('error');
  });

  it("positionne le diagnostic sur l'intégralité du contenu", () => {
    const code = 'const x = {;';
    const diags = jsDiagnostics(code);
    expect(diags[0].from).toBe(0);
    expect(diags[0].to).toBe(code.length);
  });
});
