/**
 * End-to-end wiring test for the AI generation completion email.
 *
 * Exercises the real chain — completeJob() → notifyAiGenerationCompleted() →
 * sendSystemEmail() — stubbing only the two external boundaries (the super-admin
 * settings lookup and the SMTP transport). This is what actually broke: the job
 * finished and saved, but the chain stopped at step one.
 */

const sendSystemEmailMock = jest.fn().mockResolvedValue({ success: true });
const findOneMock = jest.fn();

jest.mock('../../email/transactionalMailer', () => ({
  sendSystemEmail: (...args: any[]) => sendSystemEmailMock(...args),
}));

jest.mock('../../../models', () => ({
  getModels: () => ({ User: { findOne: (...args: any[]) => findOneMock(...args) } }),
}));

jest.mock('../../notificationService', () => ({
  notificationService: { notifyUser: jest.fn().mockResolvedValue(undefined) },
}));

jest.mock('../../../utils/requestContext', () => ({
  getRequestContext: () => ({ userId: 'user-1', organizationId: 'company-1' }),
}));

import { createJob, completeJob, failJob } from '../aiJobManager';

/** The notifier is fire-and-forget; let its async IIFE settle. */
const flush = () => new Promise((resolve) => setImmediate(resolve));

function superAdminWith(config: { enabled: boolean; recipients: string[] }) {
  findOneMock.mockReturnValue({
    lean: () => Promise.resolve({ panelSettings: { aiGenerationNotifications: config } }),
  });
}

describe('AI generation completion email — full chain', () => {
  beforeEach(() => {
    sendSystemEmailMock.mockClear();
    findOneMock.mockReset();
    superAdminWith({ enabled: true, recipients: ['ops@bizzfly.com'] });
  });

  it('emails once when a landing-page generation completes', async () => {
    const job = createJob('landing-page', 'company-1', 'landing-pages');

    completeJob(job.jobId, { title: 'Spring Launch' }, 'generated');
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
    const arg = sendSystemEmailMock.mock.calls[0][0];
    expect(arg.to).toBe('ops@bizzfly.com');
    expect(arg.subject).toBe('AI Generation Completed: Spring Launch');
    expect(arg.html).toContain('AI generation completed successfully');
    expect(arg.html).toContain('Landing Pages');
  });

  it('emails every configured recipient', async () => {
    superAdminWith({ enabled: true, recipients: ['a@x.com', 'b@x.com'] });
    const job = createJob('landing-page', 'company-1');

    completeJob(job.jobId, { title: 'Multi' }, 'generated');
    await flush();

    expect(sendSystemEmailMock.mock.calls.map((c) => c[0].to)).toEqual(['a@x.com', 'b@x.com']);
  });

  it('does not email twice if completion is signalled twice', async () => {
    const job = createJob('landing-page', 'company-1');

    completeJob(job.jobId, { title: 'Once' }, 'generated');
    completeJob(job.jobId, { title: 'Once' }, 'generated');
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
  });

  it('does not email when the generation fails', async () => {
    const job = createJob('landing-page', 'company-1');

    failJob(job.jobId, 'AI generation failed');
    await flush();

    expect(sendSystemEmailMock).not.toHaveBeenCalled();
  });

  it('respects the disabled setting', async () => {
    superAdminWith({ enabled: false, recipients: ['ops@bizzfly.com'] });
    const job = createJob('landing-page', 'company-1');

    completeJob(job.jobId, { title: 'Disabled' }, 'generated');
    await flush();

    expect(sendSystemEmailMock).not.toHaveBeenCalled();
  });

  it('does not let a mailer failure escape into the generation flow', async () => {
    sendSystemEmailMock.mockRejectedValueOnce(new Error('SMTP down'));
    const job = createJob('landing-page', 'company-1');

    expect(() => completeJob(job.jobId, { title: 'Boom' }, 'generated')).not.toThrow();
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
  });
});
