/**
 * test/policies/duplicatedMenuValidator.test.js
 *
 * Smoke tests del validator específico — confirma que las reglas
 * declaradas siguen rechazando los mismos casos que antes del refactor
 * al factory.
 */

'use strict';

const path = require('path');

const POLICY_PATH = path.resolve(
  __dirname, '..', '..', 'api', 'policies', 'duplicatedMenuValidator.js'
);

describe('policies/duplicatedMenuValidator', () => {
  let policy;
  let res;
  let next;
  let domainErrorSpy;

  beforeEach(() => {
    jest.resetModules();
    global.sails = { log: { error: jest.fn(), info: jest.fn(), warn: jest.fn() } };

    domainErrorSpy = jest.fn();
    res = {
      status:      jest.fn().mockReturnThis(),
      json:        jest.fn().mockReturnThis(),
      domainError: domainErrorSpy
    };
    next = jest.fn();

    policy = require(POLICY_PATH);
  });

  afterEach(() => {
    delete global.sails;
  });

  function makeReq(body = {}) {
    return { body };
  }

  // -----------------------------------------------------------------------
  // Body válido
  // -----------------------------------------------------------------------

  it('body válido completo → next()', async () => {
    await policy(makeReq({
      email:  { duplicateFrom: 'a@b.com', duplicateTo: 'c@d.com' },
      dryRun: true
    }), res, next);

    expect(next).toHaveBeenCalledTimes(1);
    expect(domainErrorSpy).not.toHaveBeenCalled();
  });

  it('body válido sin dryRun (opcional) → next()', async () => {
    await policy(makeReq({
      email:  { duplicateFrom: 'a@b.com', duplicateTo: 'c@d.com' }
    }), res, next);

    expect(next).toHaveBeenCalledTimes(1);
  });

  // -----------------------------------------------------------------------
  // Casos rechazados — siempre con statusCode 400 (NO 401 como antes)
  // -----------------------------------------------------------------------

  it('NO valida `access` (eso es responsabilidad de basicAuth)', async () => {
    // Sin access pero con email válido → este validator pasa.
    // basicAuth (que corre antes) es quien responderá 401.
    await policy(makeReq({
      email: { duplicateFrom: 'a@b.com', duplicateTo: 'c@d.com' }
    }), res, next);

    expect(next).toHaveBeenCalledTimes(1);
    expect(domainErrorSpy).not.toHaveBeenCalled();
  });

  it('falta el bloque email → 400', async () => {
    await policy(makeReq({}), res, next);

    expect(next).not.toHaveBeenCalled();
    const err = domainErrorSpy.mock.calls[0][0];
    expect(err.statusCode).toBe(400);
    expect(err.errors.some(e => e.field === 'email')).toBe(true);
  });

  it('email.duplicateFrom no es email válido → 400', async () => {
    await policy(makeReq({
      email:  { duplicateFrom: 'no-es-email', duplicateTo: 'c@d.com' }
    }), res, next);

    const err = domainErrorSpy.mock.calls[0][0];
    expect(err.statusCode).toBe(400);
    expect(err.errors.some(e => e.field === 'email.duplicateFrom')).toBe(true);
  });

  it('emails iguales → 400 con mensaje específico', async () => {
    await policy(makeReq({
      email:  { duplicateFrom: 'mismo@b.com', duplicateTo: 'mismo@b.com' }
    }), res, next);

    const err = domainErrorSpy.mock.calls[0][0];
    expect(err.statusCode).toBe(400);
    const msg = err.errors.map(e => e.message).join(' ');
    expect(msg).toMatch(/no pueden ser iguales/i);
  });

  it('dryRun no boolean → 400', async () => {
    await policy(makeReq({
      email:  { duplicateFrom: 'a@b.com', duplicateTo: 'c@d.com' },
      dryRun: 'sí, claro'
    }), res, next);

    const err = domainErrorSpy.mock.calls[0][0];
    expect(err.statusCode).toBe(400);
    expect(err.errors.some(e => e.field === 'dryRun')).toBe(true);
  });

  // -----------------------------------------------------------------------
  // Regression test: ya NO responde 401 (era el bug original)
  // -----------------------------------------------------------------------

  it('NUNCA responde 401 — los errores de validación son 400', async () => {
    await policy(makeReq({
      email: { duplicateFrom: 'igual@x.com', duplicateTo: 'igual@x.com' }
    }), res, next);

    if (domainErrorSpy.mock.calls.length > 0) {
      const err = domainErrorSpy.mock.calls[0][0];
      expect(err.statusCode).not.toBe(401);
      expect(err.statusCode).toBe(400);
    }
    if (res.status.mock.calls.length > 0) {
      expect(res.status).not.toHaveBeenCalledWith(401);
    }
  });
});
