import { BaseObject, ImageTexture, Math, ImageColorFormat, ImageFilterType, ImageWrapType } from '@uino/thing';
import { PanoObject } from "./PanoObject";
import { PanoGraph } from "./PanoGraph";
import { FadeSwitcher } from "./switchers/FadeSwitcher";
import { StretchSwitcher } from "./switchers/StretchSwitcher";
import { PanoramaAnimationType } from "../../const";
import { Utils } from '../../common/Utils';

/**
 * @class Panorama
 * @summary 全景图类,用于在三维场景中创建可交互漫游的全景图系统。
 * 支持多张全景图以图结构组织,通过位置坐标定义全景节点之间的空间关系,
 * 用户可在不同全景节点间切换浏览,支持淡入淡出(Fade)和拉伸过渡(Stretch)两种切换动画。
 * 适用于室内漫游、街景浏览、虚拟看房、景区导览等场景。
 * @extends THING.BaseObject
 * @memberof THING
 * @public
 * @example
 * // 创建多张全景图构成的漫游链路
 * const datas = [
 *   {uri: './pano/room1.jpg', rotationY: 0, position: [-30, 0, 0], link: [1]},
 *   {uri: './pano/room2.jpg', rotationY: 0, position: [-20, 0, 0], link: [0, 2]},
 *   {uri: './pano/room3.jpg', rotationY: 0, position: [-10, 0, 0], link: [1, 3]},
 *   {uri: './pano/room4.jpg', rotationY: 0, position: [0, 0, 0], link: [2]}
 * ];
 * const panorama = new THING.EXTEND.Panorama({ data: datas, firstIndex: 0 });
 * 
 * // 切换到索引 2 的全景图
 * panorama.changePano({
 *   link: { from: 0, to: 2 },
 *   time: 500,
 *   animationType: THING.EXTEND.PanoramaAnimationType.Fade,
 *   onComplete: function() {
 *     console.log('全景切换完成');
 *   }
 * });
 */
class Panorama extends BaseObject {

	/**
	 * 构造函数
	 * @param {object} param
	 * @param {Array<Object>} param.data 全景图的所有数据
	 * @param {number} param.firstIndex 初始化时加载的全景图数据索引,默认为0
	 * @param {Function} param.onComplete 创建全景图后的完成回调函数,默认为null
	 */
	constructor(param = {}) {
		super(param);

		this._data = param['data'];
		this._currentIndex = param['firstIndex'] || 0;
		this._radius = param['radius'];
		this._completeCallback = Utils.parseValue(param['onComplete'], param['complete']);

		this._graph = new PanoGraph();
		this._panoArray = [];
		this._createPanos();
		this._initData();

		this._fadeSwitcher = new FadeSwitcher();
		this._stretchSwitcher = new StretchSwitcher();
		this._currentSwitcher = this._stretchSwitcher;
		this._animationType = PanoramaAnimationType.Stretch;

		this.onAddTickableObject();
	}

	_createPanos() {
		this._data.forEach((info, index) => {
			const texture = new ImageTexture({
				colorFormat: ImageColorFormat.RGB,
				generateMipmaps: false,
				minFilterType: ImageFilterType.LinearFilter,
				magFilterType: ImageFilterType.LinearFilter,
				anisotropy: 1,
				wrapType: ImageWrapType.ClampToEdge
			});

			const pano = new PanoObject({ imageUrl: info.uri, radius: this._radius });
			pano._index = index;

			pano.angles = [pano.angles[0], info.rotationY, pano.angles[2]];

			pano.style.image = texture;
			pano.style.opacity = 0;
			pano.visible = false;

			if (index === this._currentIndex) {
				pano.loadTexture().then(() => {
					if (this._completeCallback) {
						this._completeCallback();
					}
				});

				pano.style.opacity = 1;
				pano.visible = true;
			}

			this.add(pano);

			this._panoArray.push(pano);
		});
	}

	_initData() {
		let direction = [0, 0, 0];
		this._data.forEach((info, index) => {
			info.link.forEach(_index => {
				const _info = this._data[_index];

				direction[0] = _info.position[0] - info.position[0];
				direction[1] = _info.position[1] - info.position[1];
				direction[2] = _info.position[2] - info.position[2];

				this._graph.link(this._panoArray[index], this._panoArray[_index], Math.normalizeVector(direction));
			});
		});
	}

	_setAnimationType(value) {
		switch (value) {
			case PanoramaAnimationType.Fade:
				this._currentSwitcher = this._fadeSwitcher;
				this._animationType = value;
				break;
			case PanoramaAnimationType.Stretch:
				this._currentSwitcher = this._stretchSwitcher;
				this._animationType = value;
				break;
			default:
				break;
		}
	}

	getType() {
		return 'Pano';
	}

	onUpdate(deltaTime) {
		this._currentSwitcher.update(deltaTime);
	}

	dispose() {
		this._node.dispose();
	}

	/**
	 * 切换全景图
	 * @param {object} param
	 * @param {object} param.link 全景图数据,例如 { uri: './pano/uino/IMG_20220909_102355_00_003.jpg', rotationY: 0, position: [-30, 0, 0], link: [1] }
	 * @param {number} param.time 全景图动画的时间
	 * @param {PanoramaAnimationType} param.animationType 全景图动画类型
	 * @param {Function} param.onUpdate 播放全景图动画时的更新回调函数
	 * @param {Function} param.onComplete 全景图动画完成后的回调函数
	 * @public
	 */
	changePano(param) {
		const { link, time, animationType } = param;
		const onUpdate = Utils.parseValue(param['onUpdate'], param['update']);
		const onComplete = Utils.parseValue(param['onComplete'], param['complete']);
		const that = this;
		const linkObject = this._graph.getLink(link.from, link.to);

		if (animationType) {
			this._setAnimationType(animationType);
		}

		linkObject.to.loadTexture().then((ev) => {
			linkObject.to.visible = true;

			this._currentSwitcher.run(linkObject, {
				time: time || 400
			}).onUpdate(function (object, elapsed) {
				if (onUpdate) {
					onUpdate(elapsed);
				}
			}).onComplete(function () {
				linkObject.from.visible = false;

				that._currentIndex = link.to;

				if (onComplete) {
					onComplete();
				}
			});
		});
	}

	/**
	 * 获取可以从指定全景图索引直接切换的所有全景图信息
	 * @param {number} index 我们想要获取信息的全景图索引,默认为this.currentIndex
	 * @return {Array<Object>} 例如 [{ from: 3, to: 2, direction: [-1,0,0] }]
	 * @public
	 */
	getLinks(index) {
		let result = [];
		index = index === undefined ? this.currentIndex : index;

		this._graph.getLinks(this._panoArray[index]).forEach(cur => {
			result.push({ from: cur.from._index, to: cur.to._index, direction: cur.direction });
		});

		return result;
	}

	/**
	 * 获取当前全景图的索引
	 * @type {number}
	 * @public
	 */
	get currentIndex() {
		return this._currentIndex;
	}

	/**
	 * 获取当前全景图动画的切换器
	 * @type {THING.EXTEND.PanoSwitcher}
	 * @public
	 */
	get switcher() {
		return this._currentSwitcher;
	}

	/**
	 * 获取所有PanoObject对象
	 * @type {Array<THING.EXTEND.PanoObejct>}
	 * @public
	 */
	get panoArray() {
		return this._panoArray;
	}

}

export { Panorama }