import { describe, it, expect } from 'vitest';
import { renderTemplate, MissingTemplateVariableError } from './template.renderer';

describe('renderTemplate (pure)', () => {
  it('substitutes variables into subject / html / text', () => {
    const out = renderTemplate(
      { subject: 'Receipt for {{firstName}}', bodyHtml: '<p>Hi {{firstName}}</p>', bodyText: 'Hi {{firstName}}', variables: ['firstName'] },
      { firstName: 'Dana' },
    );
    expect(out.subject).toBe('Receipt for Dana');
    expect(out.html).toBe('<p>Hi Dana</p>');
    expect(out.text).toBe('Hi Dana');
  });

  // The load-bearing safety property: a customer-supplied name goes into an HTML email body.
  it('escapes HTML in the html body, but leaves subject/text verbatim (XSS)', () => {
    const out = renderTemplate(
      { subject: 'Hi {{firstName}}', bodyHtml: '<p>{{firstName}}</p>', bodyText: '{{firstName}}', variables: ['firstName'] },
      { firstName: '<script>alert(1)</script>' },
    );
    expect(out.html).toBe('<p>&lt;script&gt;alert(1)&lt;/script&gt;</p>');
    expect(out.html).not.toContain('<script>');
    expect(out.text).toBe('<script>alert(1)</script>'); // plaintext is not HTML → not escaped
  });

  it('supports {{#if}} and {{#each}}', () => {
    const out = renderTemplate(
      { bodyText: '{{#if companyName}}Company: {{companyName}}\n{{/if}}{{#each items}}- {{this}}\n{{/each}}', variables: [] },
      { companyName: 'Acme', items: ['a', 'b'] },
    );
    expect(out.text).toBe('Company: Acme\n- a\n- b\n');
  });

  it('throws when a declared variable is missing (fail loud)', () => {
    expect(() => renderTemplate({ bodyText: 'Hi {{firstName}}', variables: ['firstName'] }, {})).toThrow(MissingTemplateVariableError);
  });

  it('renders only the parts that are present', () => {
    const out = renderTemplate({ bodyText: 'code {{code}}', variables: ['code'] }, { code: '123' });
    expect(out.text).toBe('code 123');
    expect(out.subject).toBeUndefined();
    expect(out.html).toBeUndefined();
  });
});
