import { v3_dot } from "../../core/geom/vec3/v3_dot.js";
import { solveQuadratic } from "../../core/math/solveQuadratic.js";

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

/**
 * Given position of the source point, and target moving at a constant velocity, compute intercept.
 * Simple example would be {@link target} being enemy running, and {@link source} being position of our archer, given that the arrow speed is {@link sourceSpeed}, where should the archer aim at in order to hit the moving target?
 * @param {Vector3} result This is where the intercept point will be written if solution is found
 * @param {Vector3} source Where to launch a projectile from
 * @param {Vector3} target Where the target currently is
 * @param {Vector3} targetVelocity Target's current velocity vector
 * @param {number} sourceSpeed Speed of the projectile in question
 * @return {boolean} true iff there is at least one real solution
 */
export function computeInterceptPoint(
    result,
    source,
    target,
    targetVelocity,
    sourceSpeed
) {

    if (sourceSpeed < 0) {
        // negative speed is invalid
        return false;
    }

    const d_ts_x = target.x - source.x;
    const d_ts_y = target.y - source.y;
    const d_ts_z = target.z - source.z;

    // Get quadratic equation components
    const a = targetVelocity.dot(targetVelocity) - sourceSpeed * sourceSpeed;
    const b = 2 * v3_dot(targetVelocity.x, targetVelocity.y, targetVelocity.z, d_ts_x, d_ts_y, d_ts_z);

    const c = v3_dot(
        d_ts_x, d_ts_y, d_ts_z,
        d_ts_x, d_ts_y, d_ts_z
    );

    // Solve quadratic
    const root_count = solveQuadratic(q_roots, 0, a, b, c); // See quad(), below

    // Find smallest positive solution
    if (root_count > 0) {
        const root_0 = q_roots[0];
        const root_1 = q_roots[1];

        let t = Math.min(root_0, root_1);

        if (t < 0) {
            // one of the roots is negative, which would produce imaginary solution, so let's try to pick the other one
            t = Math.max(root_0, root_1);
        }

        if (t >= 0) {

            // Single write, computed from the inputs up front, so it is correct
            // even when `result` aliases `target` (a copy-then-add would read
            // `target` after overwriting it, doubling the velocity term).
            result.set(
                target.x + targetVelocity.x * t,
                target.y + targetVelocity.y * t,
                target.z + targetVelocity.z * t,
            );

            return true;

        }

        // if we got to this point, that means that both roots are imaginary, so there is no real solution

    }
    return false;
}