/**
 * Completion-email coverage for the Sales Script module.
 *
 * Sales Script has three completeJob() call sites in routes/aiContextSalesScript.ts
 * (generate, regenerate, and the streaming generator) and each passes a different
 * payload shape. These tests pin that every shape produces exactly one email on
 * success, none on failure, and that the module is named correctly.
 */

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';

const flush = () => new Promise((resolve) => setImmediate(resolve));

/** Payload from the /generate and /regenerate routes. */
const pipelinePayload = {
  scripts: [{ title: 'Cold Call — Enterprise SaaS' }, { title: 'Discovery Call' }],
  statusBreakdown: { draft: 2 },
  aiModel: 'claude-sonnet',
  provider: 'claude',
};

/** Payload from the streaming generator route. */
const streamingPayload = {
  scriptsGenerated: 3,
  scriptIds: ['a', 'b', 'c'],
  statusBreakdown: { draft: 3 },
  source: 'streaming',
  aiModel: 'glm-5.1',
  provider: 'ollama',
};

describe('Sales Script — AI generation completion email', () => {
  beforeEach(() => {
    sendSystemEmailMock.mockClear();
    findOneMock.mockReset();
    findOneMock.mockReturnValue({
      lean: () => Promise.resolve({
        panelSettings: { aiGenerationNotifications: { enabled: true, recipients: ['ops@bizzfly.com'] } },
      }),
    });
  });

  it('sends exactly one email when the pipeline generate job completes', async () => {
    const job = createJob('sales-script', 'company-1', 'sales-scripts');

    completeJob(job.jobId, pipelinePayload, 'generated');
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
    const arg = sendSystemEmailMock.mock.calls[0][0];
    expect(arg.to).toBe('ops@bizzfly.com');
    expect(arg.html).toContain('AI generation completed successfully');
    expect(arg.html).toContain('Sales Scripts');
  });

  it('sends exactly one email for the regenerate job', async () => {
    const job = createJob('sales-script', 'company-1', 'sales-scripts');

    completeJob(job.jobId, pipelinePayload, 'regenerated');
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
  });

  it('sends exactly one email for the streaming generator job', async () => {
    const job = createJob('sales-script', 'company-1', 'sales-scripts');

    completeJob(job.jobId, streamingPayload, 'generated');
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
    expect(sendSystemEmailMock.mock.calls[0][0].html).toContain('Sales Scripts');
  });

  it('does not email twice if completion is signalled twice', async () => {
    const job = createJob('sales-script', 'company-1', 'sales-scripts');

    completeJob(job.jobId, streamingPayload, 'generated');
    completeJob(job.jobId, streamingPayload, 'generated');
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
  });

  it('does not email when generation fails', async () => {
    const job = createJob('sales-script', 'company-1', 'sales-scripts');

    failJob(job.jobId, 'AI generation failed');
    await flush();

    expect(sendSystemEmailMock).not.toHaveBeenCalled();
  });

  it('does not email when the generation times out', async () => {
    const job = createJob('sales-script', 'company-1', 'sales-scripts');

    failJob(job.jobId, 'Generation timeout after 15 minutes');
    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('sales-script', 'company-1', 'sales-scripts');

    expect(() => completeJob(job.jobId, streamingPayload, 'generated')).not.toThrow();
    await flush();

    expect(sendSystemEmailMock).toHaveBeenCalledTimes(1);
  });
});
