/**
 * AI Generate — mandatory context validation (TC_062)
 *
 * The AI Generate flow must not invoke the AI service when mandatory context
 * fields (e.g. Full Name, Designation) are blank. Callers declare these via a
 * `requiredContext` array; the route returns HTTP 400 with a
 * "<Label> is required." message for each blank field and never calls the model.
 *
 * Covers:
 *   - Full Name blank                → 400, AI not called
 *   - Designation blank              → 400, AI not called
 *   - Both blank                     → 400 listing both, AI not called
 *   - Valid Full Name + Designation  → 200, AI called (bio generated)
 */

import request from 'supertest';
import express from 'express';

// --- Mocks ---------------------------------------------------------------
const mockGenerateWithAI = jest.fn();

jest.mock('../../middleware/auth', () => ({
  authenticate: (req: any, _res: any, next: any) => {
    req.user = { _id: 'user-1', id: 'user-1', role: 'admin' };
    next();
  },
  requireRole: () => (_req: any, _res: any, next: any) => next(),
}));
jest.mock('../../utils/redis', () => ({
  cacheGet: jest.fn().mockResolvedValue(null),
  cacheSet: jest.fn().mockResolvedValue(undefined),
}));
jest.mock('../../utils/aiProvider', () => ({
  generateWithAI: (...args: any[]) => mockGenerateWithAI(...args),
  // The route resolves the requested model slug before generating; the mock must
  // expose it too or the happy-path request fails before reaching generateWithAI.
  resolveModelSlug: (slugOrProvider: string | undefined) => ({ provider: slugOrProvider || 'test' }),
}));
jest.mock('../../middleware/errorHandler', () => ({
  asyncHandler: (fn: any) => fn,
}));

import aiRouter from '../ai';

describe('POST /api/ai/generate — mandatory context validation (TC_062)', () => {
  let app: express.Application;

  beforeEach(() => {
    app = express();
    app.use(express.json());
    app.use('/api/ai', aiRouter);
    jest.clearAllMocks();
    mockGenerateWithAI.mockResolvedValue({
      content: 'A polished founder bio.',
      model: 'test-model',
      provider: 'test',
      tokenUsage: { totalTokens: 10, inputTokens: 5, outputTokens: 5 },
    });
  });

  const basePrompt = 'Generate the "Bio" field for a founder.';

  it('rejects when Full Name is blank (400) and does not call the AI', async () => {
    const res = await request(app)
      .post('/api/ai/generate')
      .send({
        prompt: basePrompt,
        requiredContext: [
          { label: 'Full Name', value: '' },
          { label: 'Designation', value: 'CEO' },
        ],
      })
      .expect(400);

    expect(res.body.error).toBe('Full Name is required.');
    expect(mockGenerateWithAI).not.toHaveBeenCalled();
  });

  it('rejects when Designation is blank (400) and does not call the AI', async () => {
    const res = await request(app)
      .post('/api/ai/generate')
      .send({
        prompt: basePrompt,
        requiredContext: [
          { label: 'Full Name', value: 'Rohan' },
          { label: 'Designation', value: '   ' }, // whitespace-only counts as blank
        ],
      })
      .expect(400);

    expect(res.body.error).toBe('Designation is required.');
    expect(mockGenerateWithAI).not.toHaveBeenCalled();
  });

  it('lists all missing fields when both are blank (400)', async () => {
    const res = await request(app)
      .post('/api/ai/generate')
      .send({
        prompt: basePrompt,
        requiredContext: [
          { label: 'Full Name', value: '' },
          { label: 'Designation', value: null },
        ],
      })
      .expect(400);

    expect(res.body.error).toBe('Full Name is required. Designation is required.');
    expect(mockGenerateWithAI).not.toHaveBeenCalled();
  });

  it('generates the bio when Full Name and Designation are provided (200)', async () => {
    const res = await request(app)
      .post('/api/ai/generate')
      .send({
        prompt: basePrompt,
        noCache: true,
        requiredContext: [
          { label: 'Full Name', value: 'Rohan Mehta' },
          { label: 'Designation', value: 'Founder & CEO' },
        ],
      })
      .expect(200);

    expect(res.body.content).toBe('A polished founder bio.');
    expect(mockGenerateWithAI).toHaveBeenCalledTimes(1);
  });

  it('is backward-compatible: requests without requiredContext still generate', async () => {
    const res = await request(app)
      .post('/api/ai/generate')
      .send({ prompt: basePrompt, noCache: true })
      .expect(200);

    expect(res.body.content).toBe('A polished founder bio.');
    expect(mockGenerateWithAI).toHaveBeenCalledTimes(1);
  });
});
