import { CubeTexture, HemisphereLight, ImageWrapType, MathUtils, Utils, EventType } from "../main";
import { BaseComponent } from "./BaseComponent";

const __ = {
	private: Symbol('private'),
}

let _tempArray = [];
let _id = 0;

/**
 * @class DynamicSky
 * The dynamic sky.
 * @memberof THING
 * @extends THING.BaseComponent
 * @example
 * // 创建一个基础的动态天空场景
 * const app = new THING.App();
 *
 * // 创建一个基础的盒子和平面作为场景内容
 * const box = new THING.Box({
 *     position: [0, 0.5, 0]
 * });
 * const plane = new THING.Plane(20, 20);
 *
 * // 创建天空盒纹理
 * const nightSkyTexture = new THING.CubeTexture({
 *     url: {
 *         negx: './dynamicSkyData/night/negx.png', // 左
 *         negy: './dynamicSkyData/night/negy.png', // 下
 *         negz: './dynamicSkyData/night/negz.png', // 前
 *         posx: './dynamicSkyData/night/posx.png', // 右
 *         posy: './dynamicSkyData/night/posy.png', // 上
 *         posz: './dynamicSkyData/night/posz.png'  // 后
 *     }
 * });
 *
 * // 创建月亮纹理
 * const moonTexture = new THING.ImageTexture({
 *     url: './dynamicSkyData/texture/Full_Moon_glow.jpg',
 *     wrapTypeT: THING.ImageWrapType.ClampToEdge,
 *     wrapTypeS: THING.ImageWrapType.ClampToEdge,
 * });
 *
 * // 创建云层纹理
 * const cloudsTexture = new THING.ImageTexture('./dynamicSkyData/texture/Sample_Rectangular_2048.jpg');
 *
 * // 创建星星数据
 * const starsData = './dynamicSkyData/data/StarsData.bytes';
 *
 * // 启用动态天空并设置纹理
 * app.camera.dynamicSky.active = true;
 * app.camera.dynamicSky.timeline = 13;
 * app.camera.dynamicSky.nightSkyTexture = nightSkyTexture;
 * app.camera.dynamicSky.moonTexture = moonTexture;
 * app.camera.dynamicSky.starsData = starsData;
 * app.camera.dynamicSky.cloudsTexture = cloudsTexture;
 *
 * // 调整天空参数
 * app.camera.dynamicSky.lightExposure = 1.0;     // 设置光照曝光度
 * app.camera.dynamicSky.exposure = 0.8;          // 设置天空曝光度
 * app.camera.dynamicSky.sunEquatorOffset = -40;  // 设置太阳赤道偏移量
 * app.camera.dynamicSky.sunLightIntensity = 1.0; // 设置日光强度
 * app.camera.dynamicSky.moonLightIntensity = 0.2;// 设置月光强度
 * @public
 */
class CameraDynamicSkyComponent extends BaseComponent {

	/**
	 * 相机动态天空组件,用于管理相机的动态天空效果。
	 */
	constructor() {
		super();

		this[__.private] = {};
		let _private = this[__.private];

		_private.activeSkyRender = false;

		_private.envMap = new CubeTexture();
		_private._dynamicSky = Utils.createObject('DynamicSky', {
			app: this.app,
			cubeTexture: _private.envMap.getTextureResource(),
		});
		_private._dynamicSky.setTimeline(10);
		_private._light = null;

		_private._sunLightIntensity = 1.0;

		_private._moonLightIntensity = 0.2;

		_private.hemisphereLight = null;

		_private.eventListener = this._onTimelineChange.bind(this);
		_private.eventListenerTag = `CameraDynamicSkyComponent_${_id++}`;
	}

	// #region Private Functions

	/**
	 * Load the stars data
	 * @param {string | Float32Array} data
	 * @private
	 */
	async _loadStarsData(data) {
		if (Utils.isString(data)) {
			let _buffer = await Utils.loadBinaryFile(data);
			let starsData = new Float32Array(_buffer);
			return starsData;
		}
		if (!(data instanceof Float32Array)) {
			return null;
		}
	}

	/**
	 * Update the lights.
	 * @param {string | Float32Array} data
	 * @private
	 */
	_updateLights() {
		let _private = this[__.private];
		if (this._active) {
			if (this.timeline < 18.2 && this.timeline > 5.8) {
				if (_private._light) {
					_private._light.visible = true;
					_private._dynamicSky.getSunPhiAndTheta(_tempArray);
					_private._light.adapter.vertAngle = MathUtils.radToDeg(_tempArray[1]);
					_private._light.adapter.horzAngle = MathUtils.radToDeg(_tempArray[0]);
					_private._light.color = _private._dynamicSky.getSunLightColor(_tempArray);
					_private._light.intensity = _private._sunLightIntensity;
				}
			}
			else {
				if (_private._light) {
					_private._light.visible = true;
					_private._dynamicSky.getMoonPhiAndTheta(_tempArray);
					_private._light.adapter.vertAngle = MathUtils.radToDeg(_tempArray[1]);
					_private._light.adapter.horzAngle = MathUtils.radToDeg(_tempArray[0]);
					_private._light.color = _private._dynamicSky.getMoonLightColor(_tempArray);
					_private._light.intensity = _private._moonLightIntensity;
				}
			}

			if (_private._hemisphereLight) {
				_private._hemisphereLight.color = _private._dynamicSky.getHemisphereLightColor(_tempArray);
				_private._hemisphereLight.groundColor = _private._dynamicSky.getHemisphereLightGroundColor(_tempArray);
			}
		}
		// day: 5.8- 18.2
	}

	/**
	 * 获取时间线。
	 * @type {number}
	 * @default 13
	 * @private
	 */
	_getTimeline() {
		let _private = this[__.private];

		return _private._dynamicSky.getTimeline();
	}

	/**
	 * 设置时间线。
	 * @type {number}
	 * @default 10
	 * @private
	 */
	_setTimeline(value) {
		let _private = this[__.private];

		_private._dynamicSky.setTimeline(value);

		this._updateLights();
	}

	_onTimelineChange(event) {
		const timeOfDay = event.timeOfDay;
		this._setTimeline(timeOfDay / 3600);
	}

	// #endregion

	// #region BaseComponent Overrides

	onAdd(object) {
		super.onAdd(object);

		let _private = this[__.private];
		_private._light = this.app.scene.mainLight;

		// Keep it alive to prevent destroy action
		this.enable = false;
	}

	onRemove() {
		let _private = this[__.private];

		if (_private._dynamicSky) {
			_private._dynamicSky.dispose();
			_private._dynamicSky = null;
		}

		super.onRemove();
	}

	onUpdate(deltaTime) {
		let _private = this[__.private];


		if (_private._dynamicSky && this._active) {
			_private._dynamicSky.update(deltaTime);
		}
	}

	onActiveChange(value) {
		let _private = this[__.private];

		if (value) {
			if (_private.activeSkyRender) {
				this._oldBackground = this.object.background;
				this.object.background = _private.envMap;
			}

			this.app.on(EventType.TimelineChange, _private.eventListener, _private.eventListenerTag);
		}
		else {
			if (this._oldBackground) {
				this.object.background = this._oldBackground;
			}

			this.app.off(EventType.TimelineChange, _private.eventListenerTag);
		}
	}

	onImport(param) {
		this.active = Utils.parseValue(param['active'], this.active);
		this.activeSkyRender = Utils.parseValue(param['activeSkyRender'], this.activeSkyRender);
		this.timeline = Utils.parseValue(param['timeline'], this.timeline);
		this.lightExposure = Utils.parseValue(param['lightExposure'], this.lightExposure);
		this.exposure = Utils.parseValue(param['exposure'], this.exposure);
		this.sunEquatorOffset = Utils.parseValue(param['sunEquatorOffset'], this.sunEquatorOffset);
		this.lightColorGradient = Utils.parseValue(param['lightColorGradient'], this.lightColorGradient);
		this.skyColorGradient = Utils.parseValue(param['skyColorGradient'], this.skyColorGradient);
		this.groundColorGradient = Utils.parseValue(param['groundColorGradient'], this.groundColorGradient);
		this.sunLightIntensity = Utils.parseValue(param['sunLightIntensity'], this.sunLightIntensity);
		this.moonLightIntensity = Utils.parseValue(param['moonLightIntensity'], this.moonLightIntensity);

		const light = this.app.objectManager.getBaseObjectFromUUID(Utils.parseValue(param['light']))
		if (light) {
			this.light = light;
		}

		const hemisphereLight = this.app.objectManager.getBaseObjectFromUUID(Utils.parseValue(param['hemisphereLight']))
		if (hemisphereLight) {
			this.hemisphereLight = hemisphereLight;
		}
	}

	onExport() {
		let result = {
			active: this.active,
			activeSkyRender: this.activeSkyRender,
			timeline: this.timeline,
			lightExposure: this.lightExposure,
			exposure: this.exposure,
			sunEquatorOffset: this.sunEquatorOffset,
			lightColorGradient: this.lightColorGradient,
			skyColorGradient: this.skyColorGradient,
			groundColorGradient: this.groundColorGradient,
			sunLightIntensity: this.sunLightIntensity,
			moonLightIntensity: this.moonLightIntensity,
		}

		// 如果灯光不是主光源,则添加灯光的uuid(主光源是默认值)
		if (this.light && this.light != this.app.scene.mainLight) {
			result.light = this.light.uuid;
		}
		if (this.hemisphereLight) {
			result.hemisphereLight = this.hemisphereLight.uuid;
		}

		return result
	}

	// #endregion

	/**
	 * 获取/设置天空的启用状态。
	 * @type {boolean}
	 * @public
	 * @deprecated
	 */
	async init(options) {
		let _private = this[__.private];

		_private._hemisphereLight = new HemisphereLight({
			intensity: 0.2
		});

		this.app.objectManager.addKeepAliveObject(_private._hemisphereLight);

		_private._hemisphereLight._isInternalCreation_ = true;

		let nightSkyTexture = options.nightSkyTexture;
		if (nightSkyTexture) {
			_private._dynamicSky.setNightSkyTexture(nightSkyTexture.getTextureResource());
		}
		_private.nightSkyTexture = nightSkyTexture;

		let moonTexture = options.moonTexture;
		if (moonTexture) {
			moonTexture.wrapTypeT = ImageWrapType.ClampToEdge;
			moonTexture.wrapTypeS = ImageWrapType.ClampToEdge;
			_private._dynamicSky.setMoonTexture(moonTexture.getTextureResource());
		}

		let cloudsTexture = options.cloudsTexture;
		if (cloudsTexture) {
			_private._dynamicSky.setCloudsTexture(cloudsTexture.getTextureResource());
		}

		let starsData = options.starsData;
		if (starsData) {
			starsData = await this._loadStarsData(options.starsData);
			_private._dynamicSky.setStarsData(starsData);
		}

		if (this._active) {
			this._oldBackground = this.object.background;
			this.object.background = _private.envMap;
		}
	}

	/**
	 * 获取/设置天空的启用状态。
	 * @type {boolean}
	 * @public
	 * @deprecated
	 */
	get enable() {
		return this.active;
	}
	set enable(value) {
		this.activeSkyRender = value
		this.active = value;
	}

	/**
	 * 设置/获取时间线。
	 * @type {number}
	 * @default 10
	 * @public
	 * @deprecated
	 */
	get timeline() {
		return this._getTimeline();
	}
	set timeline(value) {
		this._setTimeline(value);
	}

	/**
	 * 设置天空的夜晚贴图。
	 * @type {CubeTextureResource}
	 * @public
	 */
	set nightSkyTexture(value) {
		if (!value) {
			return;
		}

		let _private = this[__.private];

		_private._dynamicSky.setNightSkyTexture(value.getTextureResource());
	}

	/**
	 * 设置天空的云层贴图。
	 * @type {ImageTextureResource}
	 * @public
	 */
	set cloudsTexture(value) {
		if (!value) {
			return;
		}
		let _private = this[__.private];

		_private._dynamicSky.setCloudsTexture(value.getTextureResource());
	}

	/**
	 * 设置天空的月亮贴图。
	 * @type {ImageTextureResource}
	 * @public
	 */
	set moonTexture(value) {
		if (!value) {
			return;
		}
		let _private = this[__.private];

		_private._dynamicSky.setMoonTexture(value.getTextureResource());
	}

	/**
	 * 设置天空的星星数据。
	 * @type {string | Float32Array}
	 * @public
	 */
	set starsData(value) {
		if (!value) {
			return;
		}
		let _private = this[__.private];

		this._loadStarsData(value).then((data) => {
			_private._dynamicSky.setStarsData(data);
		})
	}

	/**
	 * 获取天空的贴图。
	 * @type {CubeTextureResource}
	 * @public
	 */
	get envMap() {
		let _private = this[__.private];

		return _private.envMap;
	}

	/**
	 * 设置/获取纹理的尺寸。
	 * @type {Array<number>}
	 * @default - [1024,1024]
	 * @public
	 */
	set textureSize(value) {
		let _private = this[__.private];

		return _private._dynamicSky.setTextureSize(value);
	}
	get textureSize() {
		let _private = this[__.private];

		return _private._dynamicSky.getTextureSize(_tempArray);
	}

	/**
	 * 设置/获取天空的光照曝光度。
	 * @type {number}
	 * @default 1.0
	 * @public
	 */
	get lightExposure() {
		let _private = this[__.private];

		return _private._dynamicSky.getLightExposure();
	}
	set lightExposure(value) {
		let _private = this[__.private];

		_private._dynamicSky.setLightExposure(value);
		this._updateLights();
	}

	/**
	 * 设置/获取天空的曝光度。
	 * @type {number}
	 * @default 0.8
	 * @public
	 */
	get exposure() {
		let _private = this[__.private];

		return _private._dynamicSky.getExposure();
	}
	set exposure(value) {
		let _private = this[__.private];

		_private._dynamicSky.setExposure(value);
	}

	/**
	 * 设置/获取太阳赤道偏移量。
	 * @type {number}
	 * @default -40
	 * @public
	 */
	get sunEquatorOffset() {
		let _private = this[__.private];

		return _private._dynamicSky.getSunEquatorOffset();
	}
	set sunEquatorOffset(value) {
		let _private = this[__.private];

		_private._dynamicSky.setSunEquatorOffset(value);

		this._updateLights();
	}

	/**
	 * 获取主光。
	 * @type {DirectionalLight}
	 * @public
	 */
	get light() {
		let _private = this[__.private];

		return _private._light;
	}
	set light(value) {
		let _private = this[__.private];
		if (value) {
			_private._light = value

			this._updateLights()
		}
	}

	/**
	 * 获取半球光。
	 * @type {HemisphereLight}
	 * @public
	 */
	get hemisphereLight() {
		let _private = this[__.private];

		return _private._hemisphereLight;
	}
	set hemisphereLight(value) {
		let _private = this[__.private];
		if (value) {
			_private._hemisphereLight = value

			this._updateLights()
		}
	}

	/**
	 * 设置白天日光强度。
	 * @type {number}
	 * @public
	 */
	get sunLightIntensity() {
		let _private = this[__.private];

		return _private._sunLightIntensity;
	}
	set sunLightIntensity(value) {
		let _private = this[__.private];

		_private._sunLightIntensity = value;

		this._updateLights();
	}

	/**
	 * 设置夜晚日光强度。
	 * @type {number}
	 * @public
	 */
	get moonLightIntensity() {
		let _private = this[__.private];

		return _private._moonLightIntensity;
	}
	set moonLightIntensity(value) {
		let _private = this[__.private];

		_private._moonLightIntensity = value;

		this._updateLights();
	}

	/**
	 * 设置是否渲染天空盒参数。
	 * @type {boolean}
	 * @public
	 */
	set activeSkyRender(value) {
		let _private = this[__.private];
		if (_private.activeSkyRender === value) {
			return;
		}

		if (value && this.active) {
			this._oldBackground = this.object.background;

			this.object.background = _private.envMap;
		}
		else {
			if (this._oldBackground) {
				this.object.background = this._oldBackground;
			}
		}
		_private.activeSkyRender = value;

		_private._dynamicSky.setIsSkyRender(value);
	}
	get activeSkyRender() {
		let _private = this[__.private];

		return _private.activeSkyRender;
	}


	/**
	 * 设置渲染光颜色。
	 * @type {object}
	 * @default
	 * {
			0: [85 / 255, 99 / 255, 112 / 255],
			0.49: [85 / 255, 99 / 255, 112 / 255],
			0.51: [245 / 255, 173 / 255, 84 / 255],
			0.57: [249 / 255, 208 / 255, 144 / 255],
			1: [252 / 255, 222 / 255, 186 / 255]
		}
	 * @public
	 */
	get lightColorGradient() {
		let _private = this[__.private];
		return _private._dynamicSky.getLightColorGradient();
	}
	set lightColorGradient(value) {
		let _private = this[__.private];
		_private._dynamicSky.setLightColorGradient(value);
		this._updateLights();
	}

	/**
	 * 设置渲染天光颜色。
	 * @type {object}
	 * @default
	 * {
			0: [180 / 255, 220 / 255, 255 / 255],
			0.39: [180 / 255, 220 / 255, 255 / 255],
			0.51: [180 / 255, 220 / 255, 255 / 255],
			0.7: [180 / 255, 220 / 255, 255 / 255],
			1: [203 / 255, 146 / 255, 65 / 255]
		}
	 * @public
	 */
	get skyColorGradient() {
		let _private = this[__.private];
		return _private._dynamicSky.getSkyColorGradient();
	}
	set skyColorGradient(value) {
		let _private = this[__.private];
		_private._dynamicSky.setSkyColorGradient(value);
		this._updateLights();
	}

	/**
	 * 设置渲染地面光颜色。
	 * @type {object}
	 * @default
	 *{
			0: [63 / 255, 149 / 255, 255 / 255],
			0.39: [180 / 255, 220 / 255, 255 / 255],
			0.51: [180 / 255, 220 / 255, 255 / 255],
			0.7: [180 / 255, 220 / 255, 255 / 255],
			1: [63 / 255, 149 / 255, 255 / 255]
		}
	 * @public
	 */
	get groundColorGradient() {
		let _private = this[__.private];
		return _private._dynamicSky.getGroundColorGradient();
	}
	set groundColorGradient(value) {
		let _private = this[__.private];
		_private._dynamicSky.setGroundColorGradient(value);
		this._updateLights();
	}

}

export { CameraDynamicSkyComponent }