/**
 * sends a trigger when an object is hovered
 *
 *
 */

import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {BaseUserInputJsNode} from './_BaseUserInput';
import {CoreEventEmitter} from '../../../core/event/CoreEventEmitter';
import {JsConnectionPointType, JS_CONNECTION_POINT_IN_NODE_DEF, JsConnectionPoint} from '../utils/io/connections/Js';
import {Constructor} from '../../../types/GlobalTypes';
import {
	ButtonAndModifierOptionsAsString,
	ButtonsAndModifierOptionsAsString,
	DEFAULT_STATUS_OPTION,
	ModifierOptionsAsString,
	STATUS_MENU_OPTIONS,
} from '../../scene/utils/actors/rayObjectIntersection/Common';
import {JsLinesCollectionController} from './code/utils/JsLinesCollectionController';
const CONNECTION_OPTIONS = JS_CONNECTION_POINT_IN_NODE_DEF;

const INPUT_LESS_PARAM_NAMES = ['element'];

export function MouseEventConfigParamConfig<TBase extends Constructor>(Base: TBase) {
	return class Mixin extends Base {
		buttonLeft = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, {...STATUS_MENU_OPTIONS, separatorBefore: true});
		buttonMiddle = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		buttonRight = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		ctrl = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		shift = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		alt = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
	};
}
export function MouseDoubleClickConfigParamConfig<TBase extends Constructor>(Base: TBase) {
	return class Mixin extends Base {
		ctrl = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		shift = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		alt = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
	};
}

export function PointerEventConfigParamConfig<TBase extends Constructor>(Base: TBase) {
	return class Mixin extends Base {
		buttonLeft = ParamConfig.BOOLEAN(1, {separatorBefore: true});
		buttonMiddle = ParamConfig.BOOLEAN(1);
		buttonRight = ParamConfig.BOOLEAN(1);
		ctrl = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		shift = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
		alt = ParamConfig.INTEGER(DEFAULT_STATUS_OPTION, STATUS_MENU_OPTIONS);
	};
}
export class BaseMouseConfigParamsConfig extends MouseEventConfigParamConfig(NodeParamsConfig) {}
const baseMouseConfigParamsConfig = new BaseMouseConfigParamsConfig();
export class BaseMouseDoubleClickConfigParamsConfig extends MouseDoubleClickConfigParamConfig(NodeParamsConfig) {}
const baseMouseDoubleClickConfigParamsConfig = new BaseMouseDoubleClickConfigParamsConfig();
export class BasePointerConfigParamsConfig extends PointerEventConfigParamConfig(NodeParamsConfig) {}
const basePointerConfigParamsConfig = new BasePointerConfigParamsConfig();

export class BaseOnObjectPointerEventBaseJsParamsConfig extends NodeParamsConfig {
	/** @param blockObjectsBehind */
	blockObjectsBehind = ParamConfig.BOOLEAN(1);
	/** @param skipIfObjectsInFront */
	skipIfObjectsInFront = ParamConfig.BOOLEAN(0);
}
export class CPUOnObjectPointerEventJsParamsConfig extends BaseOnObjectPointerEventBaseJsParamsConfig {
	/** @param include children */
	traverseChildren = ParamConfig.BOOLEAN(1);
	/** @param pointsThreshold */
	pointsThreshold = ParamConfig.FLOAT(0.1);
	/** @param lineThreshold */
	lineThreshold = ParamConfig.FLOAT(0.1);
}
const CPUParamsConfig = new CPUOnObjectPointerEventJsParamsConfig();
export class GPUOnObjectPointerEventJsParamsConfig extends BaseOnObjectPointerEventBaseJsParamsConfig {
	/** @param alpha test */
	// alphaTest = ParamConfig.FLOAT(0.1);
}
const GPUParamsConfig = new GPUOnObjectPointerEventJsParamsConfig();

export abstract class ExtendableOnObjectPointerEventJsNode<
	T extends BaseOnObjectPointerEventBaseJsParamsConfig
> extends BaseUserInputJsNode<T> {
	override isTriggering() {
		return true;
	}
	override eventEmitter() {
		return CoreEventEmitter.CANVAS;
	}
	override initializeNode() {
		super.initializeNode();
		this.io.inputs.setNamedInputConnectionPoints([
			new JsConnectionPoint(JsConnectionPointType.OBJECT_3D, JsConnectionPointType.OBJECT_3D, CONNECTION_OPTIONS),
		]);
		this.io.connection_points.spare_params.setInputlessParamNames(INPUT_LESS_PARAM_NAMES);
	}
	protected _additionalInputs(): JsConnectionPoint<JsConnectionPointType>[] {
		return [];
	}
}
export abstract class BaseOnObjectPointerEventJsNode extends ExtendableOnObjectPointerEventJsNode<CPUOnObjectPointerEventJsParamsConfig> {
	override readonly paramsConfig = CPUParamsConfig;
}

export abstract class BaseOnObjectPointerGPUEventJsNode extends ExtendableOnObjectPointerEventJsNode<GPUOnObjectPointerEventJsParamsConfig> {
	override readonly paramsConfig = GPUParamsConfig;
}

export abstract class BaseMouseConfigJsNode extends BaseUserInputJsNode<BaseMouseConfigParamsConfig> {
	override readonly paramsConfig = baseMouseConfigParamsConfig;
}
export abstract class BaseMouseDoubleClickConfigJsNode extends BaseUserInputJsNode<BaseMouseDoubleClickConfigParamsConfig> {
	override readonly paramsConfig = baseMouseDoubleClickConfigParamsConfig;
}
export abstract class BasePointerConfigJsNode extends BaseUserInputJsNode<BasePointerConfigParamsConfig> {
	override readonly paramsConfig = basePointerConfigParamsConfig;
}
export function pointerButtonConfig(
	node: BasePointerConfigJsNode,
	linesController: JsLinesCollectionController
): ButtonAndModifierOptionsAsString {
	const left = node.variableForInputParam(linesController, node.p.buttonLeft);
	const middle = node.variableForInputParam(linesController, node.p.buttonMiddle);
	const right = node.variableForInputParam(linesController, node.p.buttonRight);
	const ctrl = node.variableForInputParam(linesController, node.p.ctrl);
	const shift = node.variableForInputParam(linesController, node.p.shift);
	const alt = node.variableForInputParam(linesController, node.p.alt);
	return {
		button: {
			left,
			middle,
			right,
		},
		modifier: {
			ctrl,
			shift,
			alt,
		},
	};
}
export function mouseButtonsConfig(
	node: BaseMouseConfigJsNode,
	linesController: JsLinesCollectionController
): ButtonsAndModifierOptionsAsString {
	const left = node.variableForInputParam(linesController, node.p.buttonLeft);
	const middle = node.variableForInputParam(linesController, node.p.buttonMiddle);
	const right = node.variableForInputParam(linesController, node.p.buttonRight);
	const ctrl = node.variableForInputParam(linesController, node.p.ctrl);
	const shift = node.variableForInputParam(linesController, node.p.shift);
	const alt = node.variableForInputParam(linesController, node.p.alt);
	return {
		button: {
			left,
			middle,
			right,
		},
		modifier: {
			ctrl,
			shift,
			alt,
		},
	};
}
export function mouseDoubleClickButtonsConfig(
	node: BaseMouseDoubleClickConfigJsNode,
	linesController: JsLinesCollectionController
): ModifierOptionsAsString {
	const ctrl = node.variableForInputParam(linesController, node.p.ctrl);
	const shift = node.variableForInputParam(linesController, node.p.shift);
	const alt = node.variableForInputParam(linesController, node.p.alt);
	return {
		modifier: {
			ctrl,
			shift,
			alt,
		},
	};
}

export enum OnObjectPointerEventGPUJsNodeInputName {
	worldPosMaterial = 'worldPosMaterial',
}

export enum OnObjectPointerEventGPUJsNodeOutputName {
	distance = 'distance',
}
