/**
 * Creates polygons between 2 lines
 *
 *
 */
import {BufferGeometry} from 'three';
import {Mesh} from 'three';
import {LineSegments} from 'three';
import {BaseSopNodeType, TypedSopNode} from './_Base';
import {CoreGeometryUtilCurve} from '../../../core/geometry/util/Curve';
import {CoreGeometryOperationSkin} from '../../../core/geometry/operation/Skin';
import {CoreGroup} from '../../../core/geometry/Group';

import {NodeParamsConfig} from '../utils/params/ParamsConfig';
import {arrayCompact, arraySortBy} from '../../../core/ArrayUtils';
import {SopType} from '../../poly/registers/nodes/types/Sop';
class SkinSopParamsConfig extends NodeParamsConfig {}
const ParamsConfig = new SkinSopParamsConfig();

export class SkinSopNode extends TypedSopNode<SkinSopParamsConfig> {
	override paramsConfig = ParamsConfig;
	static override type() {
		return SopType.SKIN;
	}

	override initializeNode() {
		this.io.inputs.setCount(1, 2);
	}

	override cook(inputCoreGroups: CoreGroup[]) {
		const inputs = this.io.inputs.inputs()
		const compactInputs:BaseSopNodeType[]=[] 
		arrayCompact(inputs,compactInputs)
		const inputsCount = 
		compactInputs.length;
		switch (inputsCount) {
			case 1:
				return this.process_one_input(inputCoreGroups);
			case 2:
				return this.process_two_inputs(inputCoreGroups);
			default:
				return this.states.error.set('inputs count not valid');
		}
	}

	process_one_input(input_contents: CoreGroup[]) {
		const core_group0 = input_contents[0];
		const line_segments0 = this._getLineSegments(core_group0);

		const geometries: BufferGeometry[] = [];
		if (line_segments0) {
			const first_line_segment = line_segments0[0] as Mesh;
			if (first_line_segment) {
				const src_geometries = CoreGeometryUtilCurve.line_segment_to_geometries(first_line_segment);
				if (src_geometries) {
					src_geometries.forEach((src_geometry, i) => {
						if (i > 0) {
							const prev_src_geometry = src_geometries[i - 1];

							const geometry = this._skin(prev_src_geometry, src_geometry);
							geometries.push(geometry);
						}
					});
				}
			}
		}

		this.setGeometries(geometries);
	}

	process_two_inputs(input_contents: CoreGroup[]) {
		const core_group0 = input_contents[0];
		const core_group1 = input_contents[1];
		const line_segments0 = this._getLineSegments(core_group0);
		const line_segments1 = this._getLineSegments(core_group1);
		const line_segments = arraySortBy([line_segments0, line_segments1], (array) => -array.length);
		const smallest_array = line_segments[0];
		const largest_array = line_segments[1];

		const geometries: BufferGeometry[] = [];
		smallest_array.forEach((line_segment, i) => {
			const other_line_segment = largest_array[i];

			if (line_segment != null && other_line_segment != null) {
				const geo = (line_segment as Mesh).geometry as BufferGeometry;
				const other_geo = (other_line_segment as Mesh).geometry as BufferGeometry;
				const geometry = this._skin(geo, other_geo);
				geometries.push(geometry);
			}
		});

		this.setGeometries(geometries);
	}

	_getLineSegments(core_group: CoreGroup) {
		return core_group.threejsObjects().filter((child) => (child as LineSegments).isLineSegments);
	}

	_skin(geometry1: BufferGeometry, geometry0: BufferGeometry) {
		// TODO: maybe instead of doing this,
		const geometry = new BufferGeometry();

		const operation = new CoreGeometryOperationSkin(geometry, geometry1, geometry0);
		operation.process();

		return geometry;
	}
}
