import { Test, TestingModule } from '@nestjs/testing';
import { MailService, ValidationAccountEmailKind, isTransientSmtpError } from './mail.service';
import { AppConfigService } from '../config/config.service';

describe('isTransientSmtpError', () => {
  it('détecte les erreurs SMTP temporaires (454, coupure auth, timeout)', () => {
    expect(isTransientSmtpError(new Error('Invalid login: 454 4.7.0 Temporary authentication failure'))).toBe(true);
    expect(isTransientSmtpError(new Error('Connection lost to authentication server'))).toBe(true);
    expect(isTransientSmtpError(Object.assign(new Error('timeout'), { code: 'ETIMEDOUT' }))).toBe(true);
    expect(isTransientSmtpError(Object.assign(new Error('auth failed'), { responseCode: 454 }))).toBe(true);
  });

  it('ignore les erreurs permanentes (mauvaise adresse, refus définitif)', () => {
    expect(isTransientSmtpError(new Error('Invalid login: 535 Authentication failed'))).toBe(false);
    expect(isTransientSmtpError(new Error('Mailbox unavailable'))).toBe(false);
  });
});

describe('MailService (ticket #28)', () => {
  let service: MailService;
  let sendEmailSpy: jest.SpyInstance;

  const mockConfigGet = jest.fn((key: string, defaultValue?: unknown) => {
    const values: Record<string, unknown> = {
      app_name: 'TestApp',
      app_url: 'https://app.test/',
      smtp_host: '127.0.0.1',
      smtp_port: 1025,
      smtp_secure: false,
      smtp_auth_required: false,
      smtp_user: '',
      smtp_password: '',
      email_from_name: 'Test',
      email_from_address: 'noreply@test',
    };
    if (key in values) return values[key];
    return defaultValue;
  });

  beforeEach(async () => {
    jest.clearAllMocks();
    const module: TestingModule = await Test.createTestingModule({
      providers: [
        MailService,
        {
          provide: AppConfigService,
          useValue: { get: mockConfigGet },
        },
      ],
    }).compile();

    service = module.get<MailService>(MailService);
    sendEmailSpy = jest.spyOn(service, 'sendEmail').mockResolvedValue(undefined);
  });

  afterEach(() => {
    sendEmailSpy.mockRestore();
  });

  it.each<[ValidationAccountEmailKind, string]>([
    ['parent', 'Compte parent validé'],
    ['am', 'Inscription validée'],
  ])('sendValidatedAccountPasswordSetupEmail (%s) utilise Handlebars + lien token', async (kind, subjectPart) => {
    const token = '11111111-2222-3333-4444-555555555555';
    await service.sendValidatedAccountPasswordSetupEmail(
      {
        email: 'user@test.fr',
        prenom: 'Jean',
        nom: 'Dupont',
        token,
        numeroDossier: '2025-000001',
      },
      kind,
    );

    expect(sendEmailSpy).toHaveBeenCalledTimes(1);
    const [, subject, html] = sendEmailSpy.mock.calls[0];
    expect(subject).toContain('TestApp');
    expect(subject).toContain(subjectPart);
    expect(html).toContain('Jean');
    expect(html).toContain('Dupont');
    expect(html).toContain('2025-000001');
    expect(html).toContain(`https://app.test/create-password?token=${encodeURIComponent(token)}`);
  });

  it('sendPasswordResetEmail utilise Handlebars + lien /reset-password', async () => {
    const token = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee';
    await service.sendPasswordResetEmail({
      email: 'u@test.fr',
      prenom: 'Marie',
      nom: 'Curie',
      token,
    });
    expect(sendEmailSpy).toHaveBeenCalledTimes(1);
    const [, subject, html] = sendEmailSpy.mock.calls[0];
    expect(subject).toContain('Réinitialisation');
    expect(html).toContain('Marie');
    expect(html).toContain(`https://app.test/reset-password?token=${encodeURIComponent(token)}`);
    expect(html).not.toContain('create-password');
  });

  it('sendResoumissionPendingEmail — accusé resoumission avec n° dossier', async () => {
    await service.sendResoumissionPendingEmail(
      'parent@test.fr',
      'Claire',
      'MARTIN',
      '2026-000024',
    );
    expect(sendEmailSpy).toHaveBeenCalledTimes(1);
    const [to, subject, html] = sendEmailSpy.mock.calls[0];
    expect(to).toBe('parent@test.fr');
    expect(subject).toContain('resoumis');
    expect(subject).toContain('2026-000024');
    expect(html).toContain('Claire');
    expect(html).toContain('2026-000024');
    expect(html).toContain('en attente de validation');
  });
});
