import { v3_distance_above_plane } from "../../../../core/geom/vec3/v3_distance_above_plane.js";
import {
    plane3_three_compute_convex_3_plane_intersection
} from "../../../../core/geom/3d/plane/plane3_three_compute_convex_3_plane_intersection.js";

/**
 *
 * @param {function(function(Plane))} traversePlanes
 * @param {number} [bias=0]
 * @returns {Function}
 */
export function buildPlanarRenderLayerClipPlaneComputationMethod(traversePlanes, bias = 0) {

    /**
     *
     * @type {number[]}
     */
    const p = [];

    const adjacentPlanePairs = [
        [],
        [],
        [],
        []
    ];

    const range = {
        near: 0,
        far: 0
    };

    let nearPlane;

    /**
     *
     * @param {Plane} objectPlane
     */
    function visitPlane(objectPlane) {

        for (let i = 0; i < 4; i++) {
            const pair = adjacentPlanePairs[i];

            const p0 = pair[0];
            const p1 = pair[1];

            const planeIntersection = plane3_three_compute_convex_3_plane_intersection(p, 0, p0, p1, objectPlane);

            if (!planeIntersection) {
                //no intersection
                continue;
            }


            const plane_normal = nearPlane.normal;

            const distanceToNearPlane = v3_distance_above_plane(p[0], p[1], p[2], plane_normal.x, plane_normal.y, plane_normal.z, nearPlane.constant);

            //update near and far plane distances
            if (distanceToNearPlane > 0 && distanceToNearPlane < range.near) {
                range.near = distanceToNearPlane;
            }

            if (distanceToNearPlane > range.far) {
                range.far = distanceToNearPlane;
            }
        }

    }

    /**
     *
     * @param {Frustum} frustum
     * @param {number} near
     * @param {number} far
     * @param {function(near:number, far:number)} visitor
     */
    return function (frustum, near, far, visitor, thisArg) {

        const frustumPlanes = frustum.planes;

        nearPlane = frustumPlanes[5];

        adjacentPlanePairs[0][0] = frustumPlanes[0];
        adjacentPlanePairs[0][1] = frustumPlanes[2];

        adjacentPlanePairs[1][0] = frustumPlanes[0];
        adjacentPlanePairs[1][1] = frustumPlanes[3];

        adjacentPlanePairs[2][0] = frustumPlanes[1];
        adjacentPlanePairs[2][1] = frustumPlanes[2];

        adjacentPlanePairs[3][0] = frustumPlanes[1];
        adjacentPlanePairs[3][1] = frustumPlanes[3];

        range.near = near;
        range.far = far;

        traversePlanes(visitPlane);

        if (range.near <= range.far) {
            visitor.call(thisArg, range.near - bias, range.far + bias);
        }
    };

}
