import type { ParallaxState, DrawContext, SceneType } from './types';
import { drawSky, drawSun, drawClouds, drawMountains, drawHills, drawWater } from './drawBase';
import { drawEcoScene } from './scenes/eco';
import { drawForestScene } from './scenes/forest';
import { drawIndustrialScene } from './scenes/industrial';
import { drawDeforestationScene } from './scenes/deforestation';
import { drawOceanScene, drawOceanWaves } from './scenes/ocean';
import { drawOilRigScene } from './scenes/oilRig';
import { drawCityScene } from './scenes/city';
import { drawPollutedCityScene } from './scenes/pollutedCity';

export type { ParallaxState, SceneType };

const SCENE_ELEMENTS: Record<Exclude<SceneType, 'transition'>, (dc: DrawContext) => void> = {
    eco: drawEcoScene,
    forest: drawForestScene,
    industrial: drawIndustrialScene,
    deforestation: drawDeforestationScene,
    ocean: drawOceanScene,
    oilRig: drawOilRigScene,
    city: drawCityScene,
    pollutedCity: drawPollutedCityScene,
};

const CUSTOM_WATER_SCENES: SceneType[] = ['ocean', 'oilRig', 'deforestation'];
const NO_MOUNTAINS_SCENES: SceneType[] = ['ocean', 'oilRig', 'deforestation'];
const NO_HILLS_SCENES: SceneType[] = ['ocean', 'oilRig'];

export function drawLandscape(
    ctx: CanvasRenderingContext2D,
    width: number,
    height: number,
    state: ParallaxState
): void {
    const dc: DrawContext = { ctx, width, height, state };
    const { sceneType, blendToScene, blendProgress } = state;

    ctx.clearRect(0, 0, width, height);

    drawSky(dc);
    drawSun(dc);
    drawClouds(dc);

    const skipMountains = NO_MOUNTAINS_SCENES.includes(sceneType) ||
        (blendToScene && NO_MOUNTAINS_SCENES.includes(blendToScene) && (blendProgress ?? 0) > 0.5);

    const skipHills = NO_HILLS_SCENES.includes(sceneType) ||
        (blendToScene && NO_HILLS_SCENES.includes(blendToScene) && (blendProgress ?? 0) > 0.5);

    if (!skipMountains) {
        drawMountains(dc);
    }
    if (!skipHills) {
        drawHills(dc);
    }

    if (sceneType === 'transition') {
        const p = state.progress;

        // Eco fades out quickly: 1.0 -> 0.0 from progress 0.0 to 0.45
        const ecoOpacity = Math.max(0, 1 - (p / 0.45));

        // Industrial fades in later: 0.0 -> 1.0 from progress 0.55 to 1.0
        const industrialOpacity = Math.max(0, (p - 0.55) / 0.45);

        if (ecoOpacity > 0.01) {
            ctx.save();
            ctx.globalAlpha = ecoOpacity;
            drawEcoScene(dc);
            ctx.restore();
        }

        // Transition Fog: Peaks at progress 0.5 to bridge the gap between scenes
        // Increased max opacity to 0.9 to fully hide the "swap"
        const fogOpacity = Math.sin(p * Math.PI) * 0.9;

        if (fogOpacity > 0.01) {
            ctx.save();
            ctx.globalAlpha = fogOpacity;
            const gradient = ctx.createLinearGradient(0, height * 0.2, 0, height);
            gradient.addColorStop(0, 'rgba(230, 230, 230, 0)');     // Transparent top
            gradient.addColorStop(0.3, 'rgba(200, 200, 200, 0.6)');   // Hazy middle
            gradient.addColorStop(1, 'rgba(160, 160, 160, 1.0)');     // Thick bottom
            ctx.fillStyle = gradient;
            ctx.fillRect(0, 0, width, height);
            ctx.restore();
        }

        if (industrialOpacity > 0.01) {
            ctx.save();
            ctx.globalAlpha = industrialOpacity;
            drawIndustrialScene(dc);
            ctx.restore();
        }
        ctx.globalAlpha = 1;
    } else if (blendToScene && blendProgress !== undefined && blendToScene !== 'transition') {
        const fromOpacity = 1 - blendProgress;
        const toOpacity = blendProgress;

        const fromDrawer = SCENE_ELEMENTS[sceneType as keyof typeof SCENE_ELEMENTS];
        const toDrawer = SCENE_ELEMENTS[blendToScene as keyof typeof SCENE_ELEMENTS];

        if (fromDrawer && fromOpacity > 0.1) {
            ctx.globalAlpha = fromOpacity;
            fromDrawer(dc);
        }
        if (toDrawer && toOpacity > 0.1) {
            ctx.globalAlpha = toOpacity;
            toDrawer(dc);
        }
        ctx.globalAlpha = 1;
    } else {
        const drawer = SCENE_ELEMENTS[sceneType as keyof typeof SCENE_ELEMENTS];
        if (drawer) {
            drawer(dc);
        }
    }

    const useCustomWater = CUSTOM_WATER_SCENES.includes(sceneType) ||
        (blendToScene && CUSTOM_WATER_SCENES.includes(blendToScene) && (blendProgress ?? 0) > 0.5);

    if (sceneType === 'ocean' || (blendToScene === 'ocean' && (blendProgress ?? 0) > 0.5)) {
        drawOceanWaves(dc);
    } else if (!useCustomWater) {
        drawWater(dc);
    }
}
