/**
 * Тесты тумана: чистые функции цвета (fogColor из env-света) и глубин слоёв
 * (fogBandStart — от камеры вдоль взгляда), кламп fog в WeatherSpec. Композит
 * и шейдер тестируются пробами с WebGL — здесь только математика.
 */
import { describe, expect, it } from 'vitest';
import { fogColor, fogBandStart, FOG_ENV_SUN, FOG_BRIGHT, FOG_BAND_START, FOG_BAND_STEP } from '../fog';
import { clampWeather } from '../weather';

describe('fogColor (цвет тумана из env-света)', () => {
    it('ambient целиком + доля солнца, умноженные на FOG_BRIGHT', () => {
        const [r, g, b] = fogColor(
            { r: 0.5, g: 0.6, b: 0.7, intensity: 0.5 },
            { r: 0, g: 0, b: 0, intensity: 0 },
        );
        expect(r).toBeCloseTo(0.25 * FOG_BRIGHT);
        expect(g).toBeCloseTo(0.3 * FOG_BRIGHT);
        expect(b).toBeCloseTo(0.35 * FOG_BRIGHT);
    });

    it('солнце входит с долей FOG_ENV_SUN (больше, чем у частиц)', () => {
        const [r] = fogColor(
            { r: 0, g: 0, b: 0, intensity: 0 },
            { r: 1, g: 1, b: 1, intensity: 2 },
        );
        expect(r).toBeCloseTo(Math.min(1, 2 * FOG_ENV_SUN * FOG_BRIGHT));
        expect(FOG_ENV_SUN).toBeGreaterThan(0.3);
    });

    it('полдень не выбеливает: кламп 0..1, ночь — тёмный туман', () => {
        const day = fogColor(
            { r: 0.58, g: 0.58, b: 0.62, intensity: 0.55 },
            { r: 1, g: 0.9, b: 0.8, intensity: 2 },
        );
        for (const c of day) expect(c).toBeLessThanOrEqual(1);
        const night = fogColor(
            { r: 0.04, g: 0.04, b: 0.07, intensity: 0.55 },
            { r: 1, g: 1, b: 1, intensity: 0.08 },
        );
        const luma = night[0]! * 0.3 + night[1]! * 0.6 + night[2]! * 0.1;
        expect(luma).toBeLessThan(0.1);
    });
});

describe('fogBandStart (глубины слоёв по дальности)', () => {
    it('старт и шаг в долях viewSize, строго по возрастанию', () => {
        expect(fogBandStart(0, 16)).toBeCloseTo(16 * FOG_BAND_START);
        expect(fogBandStart(1, 16) - fogBandStart(0, 16)).toBeCloseTo(16 * FOG_BAND_STEP);
        for (let k = 1; k < 6; k++) expect(fogBandStart(k, 16)).toBeGreaterThan(fogBandStart(k - 1, 16));
    });

    it('полоса слоёв накрывает кадр: камера на 4·viewSize от цели, полукадр ~1.12', () => {
        // ближний край кадра ~2.9·viewSize, дальний ~5.1 — первый слой до него,
        // последний внутри дальнего края
        expect(fogBandStart(0, 10)).toBeLessThan(29);
        expect(fogBandStart(5, 10)).toBeLessThan(51);
    });
});

describe('clampWeather: fog клампится как остальные поля', () => {
    it('недостающее поле — дефолт 0, лишние значения — кламп', () => {
        expect(clampWeather({}).fog).toBe(0);
        expect(clampWeather({ fog: 0.42 }).fog).toBe(0.42);
        expect(clampWeather({ fog: 5 }).fog).toBe(1);
        expect(clampWeather({ fog: -1 }).fog).toBe(0);
    });
});