import {BaseSopOperation} from './_Base';
import {CoreGroup} from '../../../core/geometry/Group';
import {IcosahedronGeometry, BufferGeometry, Vector2, Vector3, Box3} from 'three';
import {InputCloneMode} from '../../../engine/poly/InputCloneMode';
import {isBooleanTrue} from '../../../core/BooleanValue';
import {DefaultOperationParams} from '../../../core/operations/_Base';
import {ObjectType} from '../../../core/geometry/Constant';
import {SphereBuilder} from '../../../core/geometry/builders/SphereBuilder';
const tmpBox = new Box3();
const tmpSize = new Vector3();
const tmpCenter = new Vector3();
interface SphereSopParams extends DefaultOperationParams {
	type: number;
	radius: number;
	resolution: Vector2;
	open: boolean;
	phiStart: number;
	phiLength: number;
	thetaStart: number;
	thetaLength: number;
	detail: number;
	center: Vector3;
	asLines: boolean;
}

enum SphereType {
	DEFAULT = 'default',
	ISOCAHEDRON = 'isocahedron',
}
type SphereTypes = {[key in SphereType]: number};
export const SPHERE_TYPE: SphereTypes = {
	default: 0,
	isocahedron: 1,
};
export const SPHERE_TYPES: Array<SphereType> = [SphereType.DEFAULT, SphereType.ISOCAHEDRON];

export class SphereSopOperation extends BaseSopOperation {
	static override readonly DEFAULT_PARAMS: SphereSopParams = {
		type: SPHERE_TYPE.default,
		radius: 1,
		resolution: new Vector2(30, 30),
		open: false,
		phiStart: 0,
		phiLength: Math.PI * 2,
		thetaStart: 0,
		thetaLength: Math.PI,
		detail: 1,
		center: new Vector3(0, 0, 0),
		asLines: false,
	};
	static override readonly INPUT_CLONED_STATE = InputCloneMode.NEVER;
	static override type(): Readonly<'sphere'> {
		return 'sphere';
	}

	override cook(inputCoreGroups: CoreGroup[], params: SphereSopParams) {
		const coreGroup = inputCoreGroups[0];
		const object = coreGroup ? this._cookWithInput(coreGroup, params) : this._cookWithoutInput(params);
		if (this._node) {
			object.name = this._node.name();
		}
		return this.createCoreGroupFromObjects([object]);
	}
	private _cookWithoutInput(params: SphereSopParams) {
		const geometry = this._createRequiredGeometry(params);
		geometry.translate(params.center.x, params.center.y, params.center.z);
		const object = this._createSphereObject(geometry, params);
		return object;
	}
	private _cookWithInput(coreGroup: CoreGroup, params: SphereSopParams) {
		coreGroup.boundingBox(tmpBox);
		tmpBox.getSize(tmpSize);
		tmpBox.getCenter(tmpCenter);

		const geometry = this._createRequiredGeometry(params);
		geometry.scale(tmpSize.x, tmpSize.y, tmpSize.z);
		geometry.translate(params.center.x, params.center.y, params.center.z);
		geometry.translate(tmpCenter.x, tmpCenter.y, tmpCenter.z);
		const object = this._createSphereObject(geometry, params);
		return object;
	}
	private _createSphereObject(geometry: BufferGeometry, params: SphereSopParams) {
		return BaseSopOperation.createObject(geometry, params.asLines ? ObjectType.LINE_SEGMENTS : ObjectType.MESH);
	}

	private _createRequiredGeometry(params: SphereSopParams) {
		if (params.type == SPHERE_TYPE.default) {
			return this._createDefaultSphere(params);
		} else {
			return this._createDefaultIsocahedron(params);
		}
	}

	private _createDefaultSphere(params: SphereSopParams) {
		const geometry = isBooleanTrue(params.open)
			? SphereBuilder.create({
					radius: params.radius,
					widthSegments: params.resolution.x,
					heightSegments: params.resolution.y,
					phiStart: params.phiStart,
					phiLength: params.phiLength,
					thetaStart: params.thetaStart,
					thetaLength: params.thetaLength,
					asLines: params.asLines,
					open: true,
			  })
			: SphereBuilder.create({
					radius: params.radius,
					widthSegments: params.resolution.x,
					heightSegments: params.resolution.y,
					asLines: params.asLines,
					open: false,
			  });

		// if (isBooleanTrue(params.asLines)) {
		// 	// const widthSegments = Math.max( 3, Math.floor( params.resolution.x ) );
		// 	// const heightSegments = Math.max( 2, Math.floor( params.resolution.y ) );

		// 	const newIndices: number[] = [];
		// 	// for ( let iy = 0; iy < heightSegments; iy ++ ) {

		// 	// 	for ( let ix = 0; ix < widthSegments; ix ++ ) {

		// 	// 		const a = grid[ iy ][ ix + 1 ];
		// 	// 		const b = grid[ iy ][ ix ];
		// 	// 		const c = grid[ iy + 1 ][ ix ];
		// 	// 		const d = grid[ iy + 1 ][ ix + 1 ];

		// 	// 		if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
		// 	// 		if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );

		// 	// 	}

		// 	// }
		// 	// geometry.setIndex(indices);
		// 	const currentIndices: number[] = geometry.getIndex()!.array as number[];
		// 	const facesCount = currentIndices.length / 3;
		// 	for (let faceIndex = 0; faceIndex < facesCount; faceIndex += 2) {
		// 		const a = currentIndices[faceIndex];
		// 		const b = currentIndices[faceIndex + 1];
		// 		// const c = currentIndices[faceIndex+2]
		// 		newIndices.push(a, b);
		// 		// newIndices.push(a,c)
		// 	}
		// }

		return geometry;
	}
	private _createDefaultIsocahedron(params: SphereSopParams) {
		return new IcosahedronGeometry(params.radius, params.detail);
	}
}
