import {
  getSparkleOpacity,
  SPARKLE_STAR_COUNT,
  SPARKLE_TWINKLE_RATIO,
  TWINKLE_MIN_OPACITY,
} from './utils';

describe('getSparkleOpacity', () => {
  it('returns 1 when animation is inactive', () => {
    expect(getSparkleOpacity(0, 0, false)).toBe(1);
    expect(getSparkleOpacity(0.5, 1, false)).toBe(1);
    expect(getSparkleOpacity(0.9, 2, false)).toBe(1);
  });

  it('returns 1 at the start of the twinkle wave', () => {
    expect(getSparkleOpacity(0, 0, true)).toBe(1);
  });

  it('returns minimum opacity at the peak of the twinkle wave', () => {
    const cycleProgress = SPARKLE_TWINKLE_RATIO / 2;

    expect(getSparkleOpacity(cycleProgress, 0, true)).toBe(TWINKLE_MIN_OPACITY);
  });

  it('returns 1 outside the twinkle window', () => {
    expect(getSparkleOpacity(SPARKLE_TWINKLE_RATIO, 0, true)).toBe(1);
    expect(getSparkleOpacity(0.8, 0, true)).toBe(1);
  });

  it('produces different opacities per star at the same cycle progress', () => {
    const cycleProgress = 0.1;
    const opacities = Array.from({length: SPARKLE_STAR_COUNT}, (_, starIndex) =>
      getSparkleOpacity(cycleProgress, starIndex, true),
    );

    expect(new Set(opacities).size).toBeGreaterThan(1);
  });

  it('wraps negative local phase correctly', () => {
    const cycleProgress = 0.05;
    const starIndex = 2;

    expect(getSparkleOpacity(cycleProgress, starIndex, true)).toBeLessThan(1);
    expect(getSparkleOpacity(cycleProgress, starIndex, true)).toBeGreaterThan(
      TWINKLE_MIN_OPACITY,
    );
  });
});
