import { describe, expect, it } from 'vitest';
import { FadeState } from '../fade';

const lerpNum = (a: number, b: number, k: number): number => a + (b - a) * k;

describe('FadeState', () => {
    it('мгновенно задаёт значение при seconds = 0', () => {
        const f = new FadeState(lerpNum, 0);
        f.to(0.7);
        expect(f.value).toBe(0.7);
        expect(f.target).toBe(0.7);
        expect(f.active).toBe(false);
    });

    it('линейно идёт к цели и точно её достигает', () => {
        const f = new FadeState(lerpNum, 0);
        f.to(1, 2);
        f.update(0.5);
        expect(f.value).toBeCloseTo(0.25);
        f.update(0.5);
        expect(f.value).toBeCloseTo(0.5);
        f.update(1);
        expect(f.value).toBe(1);
        expect(f.active).toBe(false);
    });

    it('тик за пределами остатка не уводит значение дальше цели', () => {
        const f = new FadeState(lerpNum, 0);
        f.to(1, 1);
        f.update(0.25);
        f.update(10); // остаток 0.75 — лишнее не интерполируется
        expect(f.value).toBe(1);
        expect(f.active).toBe(false);
    });

    it('повторный to() в середине фейда стартует от текущего значения', () => {
        const f = new FadeState(lerpNum, 0);
        f.to(1, 4);
        f.update(1); // 0.25
        f.to(0, 2);
        expect(f.origin).toBeCloseTo(0.25);
        f.update(1);
        expect(f.value).toBeCloseTo(0.125);
        f.update(1);
        expect(f.value).toBe(0);
    });

    it('update без активного фейда — no-op', () => {
        const f = new FadeState(lerpNum, 5);
        f.update(100);
        expect(f.value).toBe(5);
    });

    it('работает с произвольным типом (lerp цветов)', () => {
        // Простейший лерп RGB-упакованного цвета по каналам.
        const lerpColor = (a: number, b: number, k: number): number => {
            const ch = (c: number, s: number) => (c >> s) & 0xff;
            let out = 0;
            for (let s = 0; s < 24; s += 8) {
                const v = Math.round(lerpNum(ch(a, s), ch(b, s), k));
                out |= v << s;
            }
            return out;
        };
        const f = new FadeState(lerpColor, 0xffffff);
        f.to(0x000000, 1);
        f.update(0.5);
        expect(f.value).toBe(0x808080);
        f.update(0.5);
        expect(f.value).toBe(0x000000);
    });
});