import {UniformColor, Uniform1f, Uniform2f, Uniform3f, UniformMatrix4f} from '../uniform_binding.ts';
import {getMercatorHorizon} from '../../geo/projection/mercator_utils.ts';
import {getAtmosphereAltitudeBlend, getGlobeCenterInViewSpace, getGlobeRadiusPixels} from '../../geo/projection/globe_utils.ts';
import {vec3} from 'gl-matrix';

import type {IReadonlyTransform} from '../../geo/transform_interface.ts';
import type {SkyPropsPossiblyEvaluated} from '../../style/sky_properties.g.ts';
import type {UniformValues, UniformLocations} from '../uniform_binding.ts';
import type {Context} from '../../webgl/context.ts';

export type SkyUniformsType = {
    'u_sky_color': UniformColor;
    'u_horizon_color': UniformColor;
    'u_horizon': Uniform2f;
    'u_horizon_normal': Uniform2f;
    'u_sky_horizon_blend': Uniform1f;
    'u_sky_blend': Uniform1f;
    'u_inv_proj_matrix': UniformMatrix4f;
    'u_globe_position': Uniform3f;
    'u_globe_radius': Uniform1f;
    'u_atmosphere_blend': Uniform1f;
};

const skyUniforms = (context: Context, locations: UniformLocations): SkyUniformsType => ({
    'u_sky_color': new UniformColor(context, locations.u_sky_color),
    'u_horizon_color': new UniformColor(context, locations.u_horizon_color),
    'u_horizon': new Uniform2f(context, locations.u_horizon),
    'u_horizon_normal': new Uniform2f(context, locations.u_horizon_normal),
    'u_sky_horizon_blend': new Uniform1f(context, locations.u_sky_horizon_blend),
    'u_sky_blend': new Uniform1f(context, locations.u_sky_blend),
    'u_inv_proj_matrix': new UniformMatrix4f(context, locations.u_inv_proj_matrix),
    'u_globe_position': new Uniform3f(context, locations.u_globe_position),
    'u_globe_radius': new Uniform1f(context, locations.u_globe_radius),
    'u_atmosphere_blend': new Uniform1f(context, locations.u_atmosphere_blend),
});

const skyUniformValues = (sky: Readonly<SkyPropsPossiblyEvaluated>, transform: IReadonlyTransform, pixelRatio: number): UniformValues<SkyUniformsType> => {
    const cosRoll = Math.cos(transform.rollInRadians);
    const sinRoll = Math.sin(transform.rollInRadians);
    const mercatorHorizon  = getMercatorHorizon(transform);
    const projectionData = transform.getProjectionData({overscaledTileID: null, applyGlobeMatrix: true, applyTerrainMatrix: true});
    const skyBlend = projectionData.projectionTransition;
    const globePosition = getGlobeCenterInViewSpace(transform);
    const globeRadius = getGlobeRadiusPixels(transform.worldSize, transform.center.lat);
    return {
        'u_sky_color': sky['sky-color'],
        'u_horizon_color': sky['horizon-color'],
        'u_horizon': [(transform.width / 2 - mercatorHorizon * sinRoll)  * pixelRatio,
            (transform.height / 2 + mercatorHorizon * cosRoll) * pixelRatio],
        'u_horizon_normal': [-sinRoll, cosRoll],
        'u_sky_horizon_blend': (sky['sky-horizon-blend'] * transform.height / 2) * pixelRatio,
        'u_sky_blend': skyBlend,
        'u_inv_proj_matrix': transform.inverseProjectionMatrix,
        'u_globe_position': globePosition,
        'u_globe_radius': globeRadius,
        'u_atmosphere_blend': sky['atmosphere-blend'] * getAtmosphereAltitudeBlend(vec3.length(globePosition) - globeRadius, globeRadius),
    };
};

export {skyUniforms, skyUniformValues};
