import * as mysql from "mysql2/promise";
import { TenantEstado } from "../control-plane/entities/tenant.entity";
import { TenantsAdminService } from "./tenants-admin.service";

jest.mock("mysql2/promise");

function createService(overrides: Record<string, any> = {}) {
  const tenant = {
    id: 42,
    codigo: "prueba",
    estado: TenantEstado.ONBOARDING,
    dbHost: "host",
    dbPort: 3306,
    dbUser: "user",
    dbPasswordEncrypted: "ENC(pass)",
    dbName: "db",
  };

  const tenantRecords = {
    findById: jest.fn(async () => tenant),
    updateEstado: jest.fn(async (id: number, estado: any) => ({
      ...tenant,
      estado,
    })),
    ...overrides.tenantRecords,
  };

  const crypto = {
    decrypt: jest.fn((blob: string) => blob.replace(/^ENC\(|\)$/g, "")),
    ...overrides.crypto,
  };

  const schemaCheck = {
    getPendingMigrations: jest.fn(async () => []),
    getColumnDeviations: jest.fn(async () => []),
    ...overrides.schemaCheck,
  };

  const tallerParametrosService = {
    getTogglesOperativosAdmin: jest.fn(async () => ({
      permiteTiendas: true,
      permiteProductosPropios: true,
      facturaHabilitada: true,
    })),
    setExplicit: jest.fn(async () => undefined),
    ...overrides.tallerParametrosService,
  };

  const service = new TenantsAdminService(
    tenantRecords as any,
    crypto as any,
    schemaCheck as any,
    {} as any, // identityService -- no usado en getResumenOperativo/activarTenant/updateTogglesOperativos
    {} as any, // tenantRegistry -- idem
    {} as any, // reconciliationService -- idem
    tallerParametrosService as any,
  );

  return {
    service,
    tenant,
    tenantRecords,
    crypto,
    schemaCheck,
    tallerParametrosService,
  };
}

describe("TenantsAdminService.getResumenOperativo", () => {
  it("lee los toggles vía TallerParametrosService, no TenantConfigService", async () => {
    const mockConn = {
      query: jest.fn(async () => [[{ c: 0 }]]),
      end: jest.fn(async () => undefined),
    };
    (mysql.createConnection as jest.Mock).mockResolvedValue(mockConn);

    const { service, tallerParametrosService } = createService();

    const resumen = await service.getResumenOperativo(42);

    expect(
      tallerParametrosService.getTogglesOperativosAdmin,
    ).toHaveBeenCalledWith(42);
    expect(resumen.toggles).toEqual({
      permiteTiendas: true,
      permiteProductosPropios: true,
      facturaHabilitada: true,
    });
  });
});

describe("TenantsAdminService.activarTenant", () => {
  it("un toggle en null (no se pudo calcular) bloquea igual que un conteo en null", async () => {
    const { service } = createService();
    jest.spyOn(service, "getEstadoDetallado").mockResolvedValue({
      tenant: {} as any,
      acceso: { ok: true },
      migracionesPendientes: [],
      desviaciones: [],
    });
    jest.spyOn(service, "getResumenOperativo").mockResolvedValue({
      tiendas: 0,
      tiendasConFacturacionPos: 5,
      productos: 5,
      toggles: {
        permiteTiendas: null,
        permiteProductosPropios: true,
        facturaHabilitada: true,
      },
    });

    await expect(service.activarTenant(42)).rejects.toThrow(
      /no hay ninguna tienda creada/,
    );
  });

  it("un toggle en false SÍ se salta el chequeo correspondiente", async () => {
    const { service } = createService();
    jest.spyOn(service, "getEstadoDetallado").mockResolvedValue({
      tenant: {} as any,
      acceso: { ok: true },
      migracionesPendientes: [],
      desviaciones: [],
    });
    jest.spyOn(service, "getResumenOperativo").mockResolvedValue({
      tiendas: 0,
      tiendasConFacturacionPos: 5,
      productos: 5,
      toggles: {
        permiteTiendas: false,
        permiteProductosPropios: true,
        facturaHabilitada: true,
      },
    });

    await expect(service.activarTenant(42)).resolves.toBeDefined();
  });
});

describe("TenantsAdminService.updateTogglesOperativos", () => {
  it("escribe en taller_parametros vía setExplicit, con el actor plataforma (0), no en tenant_config", async () => {
    const { service, tallerParametrosService } = createService();

    await service.updateTogglesOperativos(42, { permiteTiendas: false });

    expect(tallerParametrosService.setExplicit).toHaveBeenCalledWith(
      42,
      "tiendas.permite_crear",
      false,
      0,
      { allowOnboarding: true },
    );
  });

  it("solo escribe los campos presentes en el DTO", async () => {
    const { service, tallerParametrosService } = createService();

    await service.updateTogglesOperativos(42, { facturaHabilitada: false });

    expect(tallerParametrosService.setExplicit).toHaveBeenCalledTimes(1);
    expect(tallerParametrosService.setExplicit).toHaveBeenCalledWith(
      42,
      "facturacion.usa_facturacion",
      false,
      0,
      { allowOnboarding: true },
    );
  });
});
