/**
 * get an object properties
 *
 *
 */

import {ParamlessTypedJsNode} from './_Base';
import {JsConnectionPoint, JsConnectionPointType, JS_CONNECTION_POINT_IN_NODE_DEF} from '../utils/io/connections/Js';
import {inputObject3D} from './_BaseObject3D';
import {JsLinesCollectionController} from './code/utils/JsLinesCollectionController';
import {Poly} from '../../Poly';
import {PrimitiveArray, VectorArray} from './code/assemblers/_BaseJsPersistedConfigUtils';
import {Quaternion, Vector3} from 'three';
// import {
// 	Vector3,
// 	Quaternion,
// 	Object3D,
// } from 'three';
// import {
// 	Copyable,
// 	CreateCopyableItemFunc,
// 	updateCopyableArrayLength,
// 	updatePrimitiveArrayLength,
// } from '../../../core/ArrayCopyUtils';

const CONNECTION_OPTIONS = JS_CONNECTION_POINT_IN_NODE_DEF;

export enum GetChildrenPropertiesJsNodeOutputName {
	position = 'position',
	quaternion = 'quaternion',
	scale = 'scale',
	// matrix = 'matrix',
	visible = 'visible',
	castShadow = 'castShadow',
	receiveShadow = 'receiveShadow',
	frustumCulled = 'frustumCulled',
	// ptnum = 'ptnum',
	// id = 'id',
	// uuid = 'uuid',
	// name = 'name',
	// quaternion = 'quaternion',
	// rotation = 'rotation',
	up = 'up',
	matrixAutoUpdate = 'matrixAutoUpdate',
}
// const OBJECT_PROPERTIES: GetChildrenPropertiesJsNodeInputName[] = [
// 	GetChildrenPropertiesJsNodeInputName.position,
// 	GetChildrenPropertiesJsNodeInputName.quaternion,
// 	GetChildrenPropertiesJsNodeInputName.scale,
// 	// GetChildrenPropertiesJsNodeInputName.matrix,
// 	GetChildrenPropertiesJsNodeInputName.visible,
// 	GetChildrenPropertiesJsNodeInputName.castShadow,
// 	GetChildrenPropertiesJsNodeInputName.receiveShadow,
// 	GetChildrenPropertiesJsNodeInputName.frustumCulled,
// 	// GetChildrenPropertiesJsNodeInputName.uuid,
// 	// GetChildrenPropertiesJsNodeInputName.name,
// 	GetChildrenPropertiesJsNodeInputName.up,
// 	GetChildrenPropertiesJsNodeInputName.matrixAutoUpdate,
// ];
//  const MATERIAL_OUTPUT = 'material';

/**
 *
 * We need different arrays per property.
 * Otherwise, a downstream node which would
 * query positions and scales would receive 2 identical arrays,
 * instead of 2 distinct ones
 *
 */
// const tmpPositions: Vector3[] = [];
// const tmpQuat: Quaternion[] = [];
// const tmpScales: Vector3[] = [];
// const tmpVisibles: boolean[] = [];
// const tmpCastShadows: boolean[] = [];
// const tmpReceiveShadows: boolean[] = [];
// const tmpFrustumCulleds: boolean[] = [];
// const tmpUps: Vector3[] = [];
// const tmpMatrixAutoUpdates: boolean[] = [];
// const createVector2: CreateCopyableItemFunc<Vector2> = () => new Vector2();
// const createVector3: CreateCopyableItemFunc<Vector3> = () => new Vector3();
// const createQuaternion: CreateCopyableItemFunc<Quaternion> = () => new Quaternion();

// function updateCopyableArray<V extends Copyable>(
// 	children: Object3D[],
// 	propertyName: GetChildrenPropertiesJsNodeInputName,
// 	targetVectors: V[],
// 	createItem: CreateCopyableItemFunc<V>
// ) {
// 	updateCopyableArrayLength(targetVectors, children.length, createItem);

// 	for (let i = 0; i < children.length; i++) {
// 		const val = children[i][propertyName as GetChildrenPropertiesJsNodeInputName] as V;
// 		targetVectors[i].copy(val as any);
// 	}
// 	return targetVectors;
// }

// function updatePrimitiveArray<T extends boolean | number | string>(
// 	children: Object3D[],
// 	propertyName: GetChildrenPropertiesJsNodeInputName,
// 	targetValues: T[],
// 	defaultValue: T
// ) {
// 	updatePrimitiveArrayLength(targetValues, children.length, defaultValue);
// 	for (let i = 0; i < children.length; i++) {
// 		const val = children[i][propertyName as GetChildrenPropertiesJsNodeInputName] as T;
// 		targetValues[i] = val;
// 	}
// 	return targetValues;
// }

export class GetChildrenPropertiesJsNode extends ParamlessTypedJsNode {
	static override type() {
		return 'getChildrenProperties';
	}

	override initializeNode() {
		this.io.inputs.setNamedInputConnectionPoints([
			new JsConnectionPoint(JsConnectionPointType.OBJECT_3D, JsConnectionPointType.OBJECT_3D, CONNECTION_OPTIONS),
		]);

		this.io.outputs.setNamedOutputConnectionPoints([
			new JsConnectionPoint(GetChildrenPropertiesJsNodeOutputName.position, JsConnectionPointType.VECTOR3_ARRAY),
			new JsConnectionPoint(
				GetChildrenPropertiesJsNodeOutputName.quaternion,
				JsConnectionPointType.QUATERNION_ARRAY
			),
			new JsConnectionPoint(GetChildrenPropertiesJsNodeOutputName.scale, JsConnectionPointType.VECTOR3_ARRAY),
			// new JsConnectionPoint(
			// 	GetChildrenPropertiesJsNodeInputName.matrix,
			// 	JsConnectionPointType.MATRIX4_ARRAY
			// ),
			new JsConnectionPoint(GetChildrenPropertiesJsNodeOutputName.up, JsConnectionPointType.VECTOR3_ARRAY),
			new JsConnectionPoint(GetChildrenPropertiesJsNodeOutputName.visible, JsConnectionPointType.BOOLEAN_ARRAY),
			new JsConnectionPoint(
				GetChildrenPropertiesJsNodeOutputName.matrixAutoUpdate,
				JsConnectionPointType.BOOLEAN_ARRAY
			),
			new JsConnectionPoint(
				GetChildrenPropertiesJsNodeOutputName.castShadow,
				JsConnectionPointType.BOOLEAN_ARRAY
			),
			new JsConnectionPoint(
				GetChildrenPropertiesJsNodeOutputName.receiveShadow,
				JsConnectionPointType.BOOLEAN_ARRAY
			),
			new JsConnectionPoint(
				GetChildrenPropertiesJsNodeOutputName.frustumCulled,
				JsConnectionPointType.BOOLEAN_ARRAY
			),
			// new JsConnectionPoint(GetChildrenPropertiesJsNodeInputName.id, JsConnectionPointType.INTEGER),
			// new JsConnectionPoint(GetChildrenPropertiesJsNodeInputName.uuid, JsConnectionPointType.BOOLEAN),
			//  new JsConnectionPoint(MATERIAL_OUTPUT, JsConnectionPointType.MATERIAL),
		]);
	}

	override setLines(shadersCollectionController: JsLinesCollectionController) {
		const usedOutputNames = this.io.outputs.used_output_names();
		const object3D = inputObject3D(this, shadersCollectionController);
		const _v3 = (
			propertyName: GetChildrenPropertiesJsNodeOutputName,
			functionName: 'getChildrenPropertiesPosition' | 'getChildrenPropertiesScale' | 'getChildrenPropertiesUp',
			type: JsConnectionPointType
		) => {
			if (!usedOutputNames.includes(propertyName)) {
				return;
			}
			const varName = this.jsVarName(propertyName);
			const tmpVarName = shadersCollectionController.addVariable(this, new VectorArray([new Vector3()]));
			const func = Poly.namedFunctionsRegister.getFunction(functionName, this, shadersCollectionController);
			shadersCollectionController.addBodyOrComputed(this, [
				{
					dataType: type,
					varName,
					value: func.asString(object3D, tmpVarName),
				},
			]);
		};
		const _q = (
			propertyName: GetChildrenPropertiesJsNodeOutputName,
			functionName: 'getChildrenPropertiesQuaternion',
			type: JsConnectionPointType
		) => {
			if (!usedOutputNames.includes(propertyName)) {
				return;
			}
			const varName = this.jsVarName(propertyName);
			const tmpVarName = shadersCollectionController.addVariable(this, new VectorArray([new Quaternion()]));
			const func = Poly.namedFunctionsRegister.getFunction(functionName, this, shadersCollectionController);
			shadersCollectionController.addBodyOrComputed(this, [
				{
					dataType: type,
					varName,
					value: func.asString(object3D, tmpVarName),
				},
			]);
		};
		const _b = (
			propertyName: GetChildrenPropertiesJsNodeOutputName,
			functionName:
				| 'getChildrenPropertiesVisible'
				| 'getChildrenPropertiesMatrixAutoUpdate'
				| 'getChildrenPropertiesCastShadow'
				| 'getChildrenPropertiesReceiveShadow'
				| 'getChildrenPropertiesFrustumCulled',
			type: JsConnectionPointType
		) => {
			if (!usedOutputNames.includes(propertyName)) {
				return;
			}
			const varName = this.jsVarName(propertyName);
			const tmpVarName = shadersCollectionController.addVariable(this, new PrimitiveArray([false]));
			const func = Poly.namedFunctionsRegister.getFunction(functionName, this, shadersCollectionController);
			shadersCollectionController.addBodyOrComputed(this, [
				{
					dataType: type,
					varName,
					value: func.asString(object3D, tmpVarName),
				},
			]);
		};

		_v3(
			GetChildrenPropertiesJsNodeOutputName.position,
			'getChildrenPropertiesPosition',
			JsConnectionPointType.VECTOR3_ARRAY
		);
		_v3(
			GetChildrenPropertiesJsNodeOutputName.scale,
			'getChildrenPropertiesScale',
			JsConnectionPointType.VECTOR3_ARRAY
		);
		_v3(GetChildrenPropertiesJsNodeOutputName.up, 'getChildrenPropertiesUp', JsConnectionPointType.VECTOR3_ARRAY);
		_q(
			GetChildrenPropertiesJsNodeOutputName.quaternion,
			'getChildrenPropertiesQuaternion',
			JsConnectionPointType.QUATERNION_ARRAY
		);
		_b(
			GetChildrenPropertiesJsNodeOutputName.visible,
			'getChildrenPropertiesVisible',
			JsConnectionPointType.BOOLEAN_ARRAY
		);
		_b(
			GetChildrenPropertiesJsNodeOutputName.matrixAutoUpdate,
			'getChildrenPropertiesMatrixAutoUpdate',
			JsConnectionPointType.BOOLEAN_ARRAY
		);
		_b(
			GetChildrenPropertiesJsNodeOutputName.castShadow,
			'getChildrenPropertiesCastShadow',
			JsConnectionPointType.BOOLEAN_ARRAY
		);
		_b(
			GetChildrenPropertiesJsNodeOutputName.receiveShadow,
			'getChildrenPropertiesReceiveShadow',
			JsConnectionPointType.BOOLEAN_ARRAY
		);
		_b(
			GetChildrenPropertiesJsNodeOutputName.frustumCulled,
			'getChildrenPropertiesFrustumCulled',
			JsConnectionPointType.BOOLEAN_ARRAY
		);
	}
}
