import { cuandoEnPalabras, debeAvisar, diasHasta, proximaOcurrencia, soloDia } from './fechas-especiales.util';

const HOY = new Date(2026, 9, 6, 15, 30); // 6 de octubre de 2026, media tarde

describe('proximaOcurrencia', () => {
  it('una fecha de este año que todavía no pasó cae en este año', () => {
    expect(proximaOcurrencia(25, 12, HOY)).toEqual(new Date(2026, 11, 25));
  });

  it('una fecha que ya pasó cae en el año siguiente', () => {
    expect(proximaOcurrencia(15, 5, HOY)).toEqual(new Date(2027, 4, 15));
  });

  it('hoy cuenta como próxima ocurrencia, no como pasada', () => {
    expect(proximaOcurrencia(6, 10, HOY)).toEqual(new Date(2026, 9, 6));
  });

  /** Saltearlo dejaría a esa persona sin saludo tres años de cada cuatro. */
  it('el 29 de febrero de un año no bisiesto se corre al 1 de marzo', () => {
    expect(proximaOcurrencia(29, 2, new Date(2026, 0, 10))).toEqual(new Date(2026, 2, 1));
  });

  it('en un año bisiesto el 29 de febrero existe', () => {
    expect(proximaOcurrencia(29, 2, new Date(2028, 0, 10))).toEqual(new Date(2028, 1, 29));
  });
});

describe('diasHasta', () => {
  it('cuenta días completos ignorando la hora', () => {
    expect(diasHasta(6, 10, HOY)).toBe(0);
    expect(diasHasta(7, 10, HOY)).toBe(1);
    expect(diasHasta(13, 10, HOY)).toBe(7);
  });

  it('para una fecha ya pasada cuenta hasta el año que viene', () => {
    expect(diasHasta(5, 10, HOY)).toBe(364);
  });
});

describe('debeAvisar', () => {
  const fecha = { dia: 13, mes: 10, recordar_dias_antes: 7, ultimo_aviso_anio: null };

  it('avisa cuando entra en la ventana', () => {
    expect(debeAvisar(fecha, HOY)).toBe(true);
  });

  it('no avisa antes de la ventana', () => {
    expect(debeAvisar({ ...fecha, recordar_dias_antes: 3 }, HOY)).toBe(false);
  });

  it('avisa el mismo día del evento', () => {
    expect(debeAvisar({ ...fecha, dia: 6 }, HOY)).toBe(true);
  });

  /** `ultimo_aviso_anio` es lo que evita repetir el aviso todos los días. */
  it('no repite el aviso dentro de la misma temporada', () => {
    expect(debeAvisar({ ...fecha, ultimo_aviso_anio: 2026 }, HOY)).toBe(false);
  });

  it('el año siguiente vuelve a avisar', () => {
    expect(debeAvisar({ ...fecha, ultimo_aviso_anio: 2025 }, HOY)).toBe(true);
  });

  /**
   * Con una igualdad exacta de días, una corrida perdida —un deploy, el servidor
   * caído— se comía la fecha hasta el año siguiente.
   */
  it('si el job no corrió un día, al siguiente el aviso igual sale', () => {
    const atrasado = { dia: 8, mes: 10, recordar_dias_antes: 7, ultimo_aviso_anio: null };
    expect(diasHasta(8, 10, HOY)).toBe(2); // ya dentro de la ventana, debió avisar el día 1
    expect(debeAvisar(atrasado, HOY)).toBe(true);
  });

  it('con 0 días de anticipación avisa sólo el día del evento', () => {
    const soloElDia = { dia: 6, mes: 10, recordar_dias_antes: 0, ultimo_aviso_anio: null };
    expect(debeAvisar(soloElDia, HOY)).toBe(true);
    expect(debeAvisar({ ...soloElDia, dia: 7 }, HOY)).toBe(false);
  });
});

describe('cuandoEnPalabras', () => {
  it('traduce la distancia a algo que se pueda leer en un asunto', () => {
    expect(cuandoEnPalabras(0)).toBe('hoy');
    expect(cuandoEnPalabras(1)).toBe('mañana');
    expect(cuandoEnPalabras(7)).toBe('en 7 días');
  });
});

describe('soloDia', () => {
  it('corta la hora', () => {
    expect(soloDia(HOY)).toEqual(new Date(2026, 9, 6));
  });
});
