import {
  FLAGS_UI,
  clavesDelCatalogo,
  clavesPorAmbito,
  entradaDe,
  TALLER_PARAMETROS_CATALOGO,
} from "./taller-parametros.catalogo";

const CLAVES_OPERACION = [
  "ot.usa_fotos",
  "ot.usa_danos",
  "ot.usa_pdf_escaner",
  "ot.usa_cosas_trae",
  "ot.usa_mecanicos",
  "ot.usa_firma_cliente",
  "ot.usa_firma_recepcion",
  "ot.exige_fecha_salida",
  "ot.una_ot_por_vehiculo",
  "cotizacion.bloquea_venta_bajo_costo",
  "cotizacion.exige_motivo_cambio",
  "cotizacion.usa_link_publico",
  "ot.usa_estado_publico",
  "modulos.usa_historial",
  "modulos.usa_reportes",
  "modulos.usa_cargas_masivas",
  "modulos.usa_bitacora",
  "impresion.recepcion",
  "impresion.cotizacion",
  "impresion.entrega",
  "impresion.orden_interna",
] as const;

describe("TALLER_PARAMETROS_CATALOGO", () => {
  it("todo requeridoSi apunta a una clave real del catálogo", () => {
    for (const clave of clavesDelCatalogo()) {
      const entrada = entradaDe(clave);
      if (entrada.requeridoSi) {
        expect(TALLER_PARAMETROS_CATALOGO).toHaveProperty([
          entrada.requeridoSi,
        ]);
      }
    }
  });

  it("requeridoSi siempre apunta a una clave booleana del MISMO ámbito", () => {
    for (const clave of clavesDelCatalogo()) {
      const entrada = entradaDe(clave);
      if (entrada.requeridoSi) {
        const gate = entradaDe(entrada.requeridoSi as any);
        expect(gate.tipo).toBe("boolean");
        expect(gate.ambito).toBe(entrada.ambito);
      }
    }
  });

  it("toda clave con comportamientoAnteFallo es booleana", () => {
    for (const clave of clavesDelCatalogo()) {
      const entrada = entradaDe(clave);
      if (entrada.comportamientoAnteFallo) {
        expect(entrada.tipo).toBe("boolean");
      }
    }
  });

  it("toda clave sensible es de tipo string (nunca boolean/number/json cifrado)", () => {
    for (const clave of clavesDelCatalogo()) {
      const entrada = entradaDe(clave);
      if (entrada.sensible) {
        expect(entrada.tipo).toBe("string");
      }
    }
  });

  it("las 4 claves de gating tienen comportamientoAnteFallo declarado", () => {
    const gates = [
      "facturacion.usa_facturacion",
      "tiendas.permite_crear",
      "productos.permite_crear",
      "notificaciones.usa_whatsapp",
    ] as const;
    for (const clave of gates) {
      expect(entradaDe(clave).comportamientoAnteFallo).toBeDefined();
    }
  });

  it("las 21 claves del grupo operacion son tenant, booleanas, apagadas por default, con sección y permitir ante fallo", () => {
    expect(
      clavesDelCatalogo()
        .filter((c) => entradaDe(c).grupo === "operacion")
        .sort(),
    ).toEqual([...CLAVES_OPERACION].sort());
    for (const clave of CLAVES_OPERACION) {
      const entrada = entradaDe(clave);
      expect(entrada).toMatchObject({
        ambito: "tenant",
        tipo: "boolean",
        default: false,
        sensible: false,
        comportamientoAnteFallo: "permitir",
      });
      expect(entrada.seccion).toBeTruthy();
      expect(entrada.etiqueta).toBeTruthy();
      expect(entrada.descripcion).toBeTruthy();
    }
  });

  it("los 3 puente nacen apagados en un sitio nuevo", () => {
    expect(entradaDe("facturacion.usa_facturacion").default).toBe(false);
    expect(entradaDe("productos.permite_crear").default).toBe(false);
    expect(entradaDe("tiendas.permite_crear").default).toBe(false);
  });

  it("exige_pago_para_entrega es del grupo facturacion y nace encendido (salvaguarda)", () => {
    expect(entradaDe("facturacion.exige_pago_para_entrega")).toMatchObject({
      ambito: "tenant",
      tipo: "boolean",
      default: true,
      grupo: "facturacion",
      comportamientoAnteFallo: "permitir",
    });
  });

  it("precio_incluye_iva es por tienda, booleana, default true y sin requeridoSi", () => {
    const entrada = entradaDe("facturacion_pos.precio_incluye_iva");
    expect(entrada).toMatchObject({
      ambito: "tienda",
      tipo: "boolean",
      default: true,
      grupo: "facturacion",
    });
    expect(entrada.requeridoSi).toBeUndefined();
  });

  it("FLAGS_UI apunta solo a claves booleanas de ámbito tenant, sin repetir ninguna", () => {
    const claves = Object.values(FLAGS_UI);
    expect(new Set(claves).size).toBe(claves.length);
    for (const clave of claves) {
      expect(entradaDe(clave)).toMatchObject({
        ambito: "tenant",
        tipo: "boolean",
      });
    }
  });

  it("FLAGS_UI cubre los 4 flags históricos y todas las claves de operacion", () => {
    expect(FLAGS_UI).toMatchObject({
      usaFacturacion: "facturacion.usa_facturacion",
      permiteTiendas: "tiendas.permite_crear",
      permiteProductosPropios: "productos.permite_crear",
      usaWhatsapp: "notificaciones.usa_whatsapp",
    });
    const claves = new Set<string>(Object.values(FLAGS_UI));
    for (const clave of CLAVES_OPERACION) expect(claves.has(clave)).toBe(true);
    expect(Object.keys(FLAGS_UI)).toHaveLength(26);
  });

  it("seccion solo aparece en claves del grupo operacion", () => {
    for (const clave of clavesPorAmbito("tenant")) {
      const entrada = entradaDe(clave);
      if (entrada.seccion) expect(entrada.grupo).toBe("operacion");
    }
  });
});
