import { Texture } from "three";
import { describe, expect, it, vi } from "vitest";

import { createDefaultProjectTimeSettings } from "../../src/document/project-time-settings";
import { createDefaultWorldSettings } from "../../src/document/world-settings";
import { PrecomputedShaderSkyEnvironmentCache } from "../../src/rendering/precomputed-shader-sky-environment-cache";
import {
  resolveWorldShaderSkyEnvironmentPhaseStates,
  resolveWorldShaderSkyRenderState,
  type WorldShaderSkyRenderState
} from "../../src/rendering/world-shader-sky";
import {
  resolveRuntimeDayNightWorldState,
  resolveRuntimeTimeState
} from "../../src/runtime-three/runtime-project-time";

describe("PrecomputedShaderSkyEnvironmentCache", () => {
  it("builds representative shader environment textures once per phase-cache key", () => {
    const world = createDefaultWorldSettings();
    const time = createDefaultProjectTimeSettings();
    world.background = {
      mode: "shader"
    };
    const buildEnvironmentTexture = vi.fn(() => ({
      texture: new Texture(),
      dispose: vi.fn()
    }));
    const cache = new PrecomputedShaderSkyEnvironmentCache({
      buildEnvironmentTexture
    });
    const states = resolveWorldShaderSkyEnvironmentPhaseStates(world, time);

    cache.syncPhaseTextures(states);
    cache.syncPhaseTextures(states);

    expect(buildEnvironmentTexture).toHaveBeenCalledTimes(4);
  });

  it("blends between the active precomputed phase textures during twilight", () => {
    const world = createDefaultWorldSettings();
    const time = createDefaultProjectTimeSettings();
    const buildOrder: string[] = [];
    const phaseTextures: Record<"day" | "dawn" | "dusk" | "night", Texture> = {
      day: new Texture(),
      dawn: new Texture(),
      dusk: new Texture(),
      night: new Texture()
    };
    const blendedTexture = new Texture();
    time.sunriseTimeOfDayHours = 7;
    time.sunsetTimeOfDayHours = 20;
    time.dawnDurationHours = 2;
    time.duskDurationHours = 2;
    world.background = {
      mode: "shader"
    };
    const cache = new PrecomputedShaderSkyEnvironmentCache({
      buildEnvironmentTexture: vi.fn((state: WorldShaderSkyRenderState) => {
        buildOrder.push(state.time.dayPhase);
        return {
          texture: phaseTextures[state.time.dayPhase],
          dispose: vi.fn()
        };
      }),
      phaseBlendTextureResolver: {
        resolveBlendTexture: vi.fn().mockReturnValue(blendedTexture)
      }
    });
    const noonTime = resolveRuntimeTimeState(time, {
      timeOfDayHours: 7.5,
      dayCount: 0,
      dayLengthMinutes: 24
    });
    const noonWorld = resolveRuntimeDayNightWorldState(
      world,
      time,
      {
        timeOfDayHours: 7.5,
        dayCount: 0,
        dayLengthMinutes: 24
      },
      noonTime
    );
    const twilightSky = resolveWorldShaderSkyRenderState(
      world,
      noonWorld,
      noonTime,
      time
    );
    const states = resolveWorldShaderSkyEnvironmentPhaseStates(world, time);

    cache.syncPhaseTextures(states);

    expect(buildOrder).toEqual(["day", "dawn", "dusk", "night"]);
    expect(cache.resolveEnvironmentTexture(twilightSky!)).toBe(blendedTexture);
  });
});
