import { BaseTickableObject3D, Utils } from '@uino/thing';
import { PLYLoader } from '../../loaders/PLYLoader';
import { BinaryLoader } from '../../loaders/BinaryLoader';

/**
 * @class GaussianSplatting
 * @summary 高斯喷射类,用于在三维场景中渲染 3D Gaussian Splatting 数据。
 * 支持 .ply、.splat、.ksplat 三种格式的高斯喷射数据加载与实时渲染。
 * 注意:这里的点击事件实际用的是浏览器的click,没有走thingjs的事件逻辑
 * @public
 * @author huyang
 * @extends THING.BaseTickableObject3D
 * @memberof THING
 * @example
 * // 加载并渲染高斯喷射数据
 * const gs = new THING.EXTEND.GaussianSplatting({
 *   url: './models/scene.ply',
 *   onComplete: function() {
 *     console.log('高斯喷射数据加载完成');
 *   }
 * });
 * gs.position = [0, 0, 0];
 * 
 * // 监听点击事件,获取拾取坐标
 * gs.on('click', function(ev) {
 *   console.log('点击位置:', ev.pickedPosition);
 * });
 */
class GaussianSplatting extends BaseTickableObject3D {

 /**
   * @public
   * @summary 高斯喷射类,用于渲染高斯喷射数据
   * @param {Object} param
   * @param {String} param.url 数据url 支持后缀名为ply,splat,ksplat的高斯喷射数据
   * @param {Function} [param.onComplete] 图层创建完毕后的回调函数
   */
	constructor(param = {}) {
		super(param);
	}
	_loadData(url, resolve, reject) {
		const ext = url._getExtension();
		let loader = null;
		if (ext === 'splat' || ext === 'ksplat') {
			loader = new BinaryLoader();
		}
		else if (ext === 'ply') {
			loader = new PLYLoader();
		}
		else {
			console.error('Url does not ends with splat,ksplat or ply');
			reject();
			return;
		}
		loader.load(url, (geometry) => {
			resolve && resolve(geometry);
		}, reject);
	}
	onSetupResource(param) {
		this.onSetupURL(param);
		super.onSetupResource(param);
	}
	onLoadRenderableResource(param, resolve, reject) {
		if (this.resource.url) {
			this._loadData(this.resource.url, (data) => {
				const node = Utils.createObject('GaussianSplattingNode', { uScene: this.node._uScene, camera: this.app.camera.node._node, buffer: data });
				this.body.setNode(node);
				resolve && resolve();
			}, reject)
		}
	}
	onUpdate() {
		if (this.node._mesh) {
			this.node._mesh.update(this.app.camera.node._node, this.app.container.clientWidth, this.app.container.clientHeight);
		}
	}
	off(type, condition, callback, tag, priority, options = {}) {
		const info = Utils.parseEvent(
			type,
			condition,
			callback,
			tag,
			priority,
			options
		);
		if (this._clickCallback) {
			if (info.type.toLowerCase() === 'click') {
				const eventType = 'pointerup';
				this.app.container.ownerDocument.removeEventListener(eventType, this._clickCallback, false);
			}
			else if (info.type.toLowerCase() === 'dblclick') {
				const eventType = 'dblclick';
				this.app.container.ownerDocument.removeEventListener(eventType, this._clickCallback, false);
			}
		}
	}
	// 重写on方法 支持拾取对象的id 坐标和userData
	on(type, condition, callback, tag, priority, options = {}) {
		let result;

		const info = Utils.parseEvent(
			type,
			condition,
			callback,
			tag,
			priority,
			options
		);
		// options = { useCapture: true };
		const oldCallback = info.callback;
		this._clickCallback = (event) => {
			event.object = this;
			Object.defineProperties(event, {
				'pickedPosition': {
					get() {
						const mouse = {};
						mouse.x = (event.clientX / app.container.clientWidth) * 2 - 1;
						mouse.y = -(event.clientY / app.container.clientHeight) * 2 + 1;
						const position = event.object.app.camera.picker._getAdjustedPosition(mouse.x, mouse.y);
						const pickedPosition = event.object.node.getPickedPosition(position[0], position[1]);
						// if (pickedPosition) {
						return pickedPosition;
						// }
					}
				},
			});
			oldCallback(event);
		};
		this._clickCallback = this._clickCallback.bind(this);
		if (info.type.toLowerCase() === 'click') {
			const eventType = 'pointerup';
			result = this.app.container.ownerDocument.addEventListener(eventType, this._clickCallback, false);
		}
		else if (info.type.toLowerCase() === 'dblclick') {
			const eventType = 'dblclick';
			result = this.app.container.ownerDocument.addEventListener(eventType, this._clickCallback, false);
		}
		return result;
	}
}

export { GaussianSplatting };