import { ForbiddenException } from "@nestjs/common";
import { ProductosService } from "./productos.service";
import { ProductoLocal } from "./entities/producto-local.entity";

function createService(overrides: Record<string, any> = {}) {
  const localRepo = {
    findOne: jest.fn(async () => null),
    create: jest.fn((d: any) => d),
    save: jest.fn(async (d: any) => ({ ...d, plu: d.plu ?? "TLLP-00000001" })),
    createQueryBuilder: jest.fn(() => ({
      where: jest.fn().mockReturnThis(),
      andWhere: jest.fn().mockReturnThis(),
      orderBy: jest.fn().mockReturnThis(),
      take: jest.fn().mockReturnThis(),
      getMany: jest.fn(async () => []),
      getOne: jest.fn(async () => null),
    })),
    ...overrides.localRepo,
  };

  const erpRepo = {
    findOne: jest.fn(async () => null),
    ...overrides.erpRepo,
  };

  const tenantAccessor = {
    repositoryFor: jest.fn((entity: any) =>
      entity === ProductoLocal ? localRepo : erpRepo,
    ),
    ...overrides.tenantAccessor,
  };

  const tallerParametros = {
    getBooleanConFallback: jest.fn(async () => true),
    ...overrides.tallerParametros,
  };

  const service = new ProductosService(
    tenantAccessor as any,
    tallerParametros as any,
  );

  return {
    service,
    localRepo,
    erpRepo,
    tenantAccessor,
    tallerParametros,
  };
}

describe("ProductosService — gate de productos.permite_crear", () => {
  it("create() rechaza con ForbiddenException si el toggle está apagado", async () => {
    const tallerParametros = {
      getBooleanConFallback: jest.fn(async () => false),
    };
    const { service } = createService({ tallerParametros });

    await expect(
      service.create({ desclarga: "Aceite 5W30" } as any),
    ).rejects.toThrow(ForbiddenException);
    expect(tallerParametros.getBooleanConFallback).toHaveBeenCalledWith(
      "productos.permite_crear",
    );
  });

  it("update() rechaza con ForbiddenException si el toggle está apagado", async () => {
    const tallerParametros = {
      getBooleanConFallback: jest.fn(async () => false),
    };
    const { service } = createService({ tallerParametros });

    await expect(
      service.update("TLLP-1", { desclarga: "x" } as any),
    ).rejects.toThrow(ForbiddenException);
  });

  it("create() procede normalmente cuando el toggle está en true", async () => {
    const { service, localRepo } = createService();

    await service.create({ desclarga: "Aceite 5W30" } as any);

    expect(localRepo.save).toHaveBeenCalled();
  });

  it("create() guarda solo en taller_productos: el ERP (maeplu) no se toca", async () => {
    const { service, localRepo, erpRepo, tenantAccessor } = createService();

    await service.create({ desclarga: "Aceite 5W30" } as any);

    expect(localRepo.save).toHaveBeenCalledTimes(1);
    // Solo se lee el ERP (para no chocar con un PLU existente); nunca se escribe.
    expect(Object.keys(erpRepo)).toEqual(["findOne"]);
    for (const [entidad] of tenantAccessor.repositoryFor.mock.calls) {
      expect(entidad.name).not.toBe("MaepluMirror");
    }
  });
});
