import { WhatsappService } from "./whatsapp.service";
import { EstadoOT } from "../ots/entities/orden-trabajo.entity";

function createService(overrides: Record<string, any> = {}) {
  const clienteRepository = {
    findOne: jest.fn(async () => ({
      nombre: "Juan Perez",
      celular: "12345678",
      telefono: null,
    })),
    ...overrides.clienteRepository,
  };

  const tenantAccessor = {
    repositoryFor: jest.fn(() => clienteRepository),
    getCurrentTenantId: jest.fn(() => 42),
    ...overrides.tenantAccessor,
  };

  const otsService = {
    findById: jest.fn(async () => ({
      id: 7,
      numeroOt: "OT-1234",
      estado: EstadoOT.EN_PROCESO,
      clienteTarjeta: "2031",
      vehiculo: { placa: "P123ABC" },
    })),
    logEvento: jest.fn(async () => undefined),
    ...overrides.otsService,
  };

  const cotizacionesService = { ...overrides.cotizacionesService };

  const configService = {
    get: jest.fn((_key: string, def?: any) => def),
    ...overrides.configService,
  };

  const valores: Record<string, any> = {
    "notificaciones.usa_whatsapp": true,
    "notificaciones.whatsapp_access_token": "token-real",
    "notificaciones.whatsapp_phone_number_id": "1234567890",
    "notificaciones.whatsapp_api_version": "v25.0",
    "notificaciones.whatsapp_default_country_code": "502",
    "notificaciones.whatsapp_template_estado": "",
    "notificaciones.whatsapp_template_cotizacion": "",
    "notificaciones.whatsapp_template_language": "es_GT",
    ...overrides.valores,
  };
  const tallerParametros = {
    get: jest.fn(async (clave: string) => valores[clave]),
    ...overrides.tallerParametros,
  };

  const service = new WhatsappService(
    configService as any,
    cotizacionesService as any,
    otsService as any,
    tenantAccessor as any,
    tallerParametros as any,
  );

  return {
    service,
    clienteRepository,
    tenantAccessor,
    otsService,
    configService,
    tallerParametros,
  };
}

describe("WhatsappService.sendEstadoOt — configuración por tenant, sin fallback a env", () => {
  it("lanza un error claro si notificaciones.usa_whatsapp está apagado, sin llamar a fetch", async () => {
    const fetchMock = jest.fn();
    (global as any).fetch = fetchMock;
    const { service } = createService({
      valores: { "notificaciones.usa_whatsapp": false },
    });

    await expect(service.sendEstadoOt(7, { id: 1 })).rejects.toThrow(
      /WhatsApp no está activado/,
    );
    expect(fetchMock).not.toHaveBeenCalled();
  });

  it("lanza un error claro si falta access token o phone number id, no un error de 'undefined'", async () => {
    const fetchMock = jest.fn();
    (global as any).fetch = fetchMock;
    const { service } = createService({
      valores: { "notificaciones.whatsapp_access_token": "" },
    });

    await expect(service.sendEstadoOt(7, { id: 1 })).rejects.toThrow(
      /WhatsApp no está configurado/,
    );
    expect(fetchMock).not.toHaveBeenCalled();
  });

  it("usa el código de país del TENANT (no una constante fija) para números locales de 8 dígitos", async () => {
    const fetchMock = jest.fn(async () => ({
      ok: true,
      text: async () => JSON.stringify({ messages: [{ id: "wamid.1" }] }),
    }));
    (global as any).fetch = fetchMock;
    const { service } = createService({
      valores: { "notificaciones.whatsapp_default_country_code": "1" },
    });

    await service.sendEstadoOt(7, { id: 1 });

    // Cast necesario: jest.fn(async () => ({...})) sin parámetros tipados se
    // infiere como Mock<..., []>, así que TS ve mock.calls[0] como tupla
    // vacía. El cast preserva exactamente el comportamiento/aserciones del
    // brief, solo evita el error de compilación de ts-jest (TS2493).
    const [, requestInit] = fetchMock.mock.calls[0] as any[];
    const body = JSON.parse((requestInit as any).body);
    expect(body.to).toBe("112345678");
  });

  it("envía con éxito cuando la configuración del tenant está completa", async () => {
    const fetchMock = jest.fn(async () => ({
      ok: true,
      text: async () => JSON.stringify({ messages: [{ id: "wamid.1" }] }),
    }));
    (global as any).fetch = fetchMock;
    const { service } = createService();

    const result = await service.sendEstadoOt(7, { id: 1 });

    expect(result.ok).toBe(true);
    expect(fetchMock).toHaveBeenCalledWith(
      "https://graph.facebook.com/v25.0/1234567890/messages",
      expect.objectContaining({
        headers: expect.objectContaining({
          Authorization: "Bearer token-real",
        }),
      }),
    );
  });
});
