import { distance, subtract, dot } from "mathjs";
import { distToSegmentSquared, isPointAwayFromLineEnd, } from "../../../utils/measurement";
import { getWellHeadPosition } from "./features";
function getLineStringGeometry(well_object) {
    const geometries = well_object.geometry.geometries;
    return geometries.find((item) => item.type === "LineString");
}
export function getColor(accessor) {
    if (Array.isArray(accessor)) {
        return accessor;
    }
    return (object, objectInfo) => {
        var _a;
        if (typeof accessor === "function") {
            const colorFunc = accessor;
            // info object is arguably required, but there's too many spots that don't pass it along atm
            // @ts-expect-error -- @ander2303
            const color = colorFunc(object, objectInfo);
            if (color) {
                return color;
            }
        }
        return (_a = object.properties) === null || _a === void 0 ? void 0 : _a.color;
    };
}
/**
 * Get trajectory transparency based on alpha of trajectory color
 */
function isTrajectoryTransparent(well_object, color_accessor) {
    var _a;
    let alpha;
    const accessor = getColor(color_accessor);
    if (typeof accessor === "function") {
        alpha = (_a = accessor(well_object)) === null || _a === void 0 ? void 0 : _a[3];
    }
    else {
        alpha = accessor === null || accessor === void 0 ? void 0 : accessor[3];
    }
    return alpha === 0;
}
/**
 * Get trajectory data from LineString Geometry if it's visible (checking
 * trajectory visiblity based on line color)
 */
export function getTrajectory(well_object, color_accessor) {
    var _a;
    if (!isTrajectoryTransparent(well_object, color_accessor))
        return (_a = getLineStringGeometry(well_object)) === null || _a === void 0 ? void 0 : _a.coordinates;
    else
        return undefined;
}
export function getMdsInRange(mdArray, 
// We assume the range is already sanitized (aka: mdStart < mdEnd)
mdStart, mdEnd) {
    const mdSection = [];
    mdSection.push(mdStart);
    for (let index = 0; index < mdArray.length; index++) {
        const md = mdArray[index];
        // Equal mds are skipped, since they're added at the end
        if (md <= mdStart)
            continue;
        if (md >= mdEnd)
            break;
        mdSection.push(md);
    }
    mdSection.push(mdEnd);
    return mdSection;
}
// Interpolates point closest to the coords on trajectory
export function interpolateDataOnTrajectory(coord, data, trajectory) {
    // if number of data points in less than 1 or
    // length of data and trajectory are different we cannot interpolate.
    if (data.length <= 1 || data.length != trajectory.length)
        return null;
    // Identify closest well path leg to coord.
    const segment_index = getSegmentIndex(coord, trajectory);
    const index0 = segment_index;
    const index1 = index0 + 1;
    // Get the nearest data.
    const data0 = data[index0];
    const data1 = data[index1];
    // Get the nearest survey points.
    const survey0 = trajectory[index0];
    const survey1 = trajectory[index1];
    // To avoid interpolating longer than the actual wellbore path we ignore the coordinate if it's moved beyond the last line
    if (index1 === trajectory.length - 1 &&
        isPointAwayFromLineEnd(coord, [survey0, survey1])) {
        coord = survey1;
    }
    const dv = distance(survey0, survey1);
    if (dv === 0) {
        return null;
    }
    // Calculate the scalar projection onto segment.
    const v0 = subtract(coord, survey0);
    const v1 = subtract(survey1, survey0);
    // scalar_projection in interval [0,1]
    const scalar_projection = dot(v0, v1) / (dv * dv);
    // Interpolate data.
    return data0 * (1.0 - scalar_projection) + data1 * scalar_projection;
}
export function getMd(coord, feature, accessor) {
    var _a, _b;
    if (!((_b = (_a = feature.properties) === null || _a === void 0 ? void 0 : _a["md"]) === null || _b === void 0 ? void 0 : _b[0]) || !feature.geometry)
        return null;
    const measured_depths = feature.properties.md[0];
    const trajectory3D = getTrajectory(feature, accessor);
    if (trajectory3D == undefined)
        return null;
    let trajectory;
    // In 2D view coord is of type Point2D and in 3D view it is Point3D,
    // so use appropriate trajectory for interpolation
    if (coord.length == 2) {
        const trajectory2D = trajectory3D.map((v) => {
            return v.slice(0, 2);
        });
        trajectory = trajectory2D;
    }
    else {
        trajectory = trajectory3D;
    }
    return interpolateDataOnTrajectory(coord, measured_depths, trajectory);
}
export function getTvd(coord, feature, accessor) {
    var _a;
    const trajectory3D = getTrajectory(feature, accessor);
    // if trajectory is not found or if it has a data single point then get tvd from well head
    if (trajectory3D == undefined || (trajectory3D === null || trajectory3D === void 0 ? void 0 : trajectory3D.length) <= 1) {
        const wellhead_xyz = getWellHeadPosition(feature);
        return (_a = wellhead_xyz === null || wellhead_xyz === void 0 ? void 0 : wellhead_xyz[2]) !== null && _a !== void 0 ? _a : null;
    }
    let trajectory;
    // For 2D view coord is Point2D and for 3D view it is Point3D
    if (coord.length == 2) {
        const trajectory2D = trajectory3D === null || trajectory3D === void 0 ? void 0 : trajectory3D.map((v) => {
            return v.slice(0, 2);
        });
        trajectory = trajectory2D;
    }
    else {
        trajectory = trajectory3D;
    }
    const tvds = trajectory3D.map((v) => {
        return v[2];
    });
    // TVD goes downwards, so it's reversed
    return interpolateDataOnTrajectory(coord, tvds, trajectory);
} // Identify closest path leg to coord.
export function getSegmentIndex(coord, path) {
    let min_d = Number.MAX_VALUE;
    let segment_index = 0;
    for (let i = 0; i < (path === null || path === void 0 ? void 0 : path.length) - 1; i++) {
        const d = distToSegmentSquared(path[i], path[i + 1], coord);
        if (d > min_d)
            continue;
        segment_index = i;
        min_d = d;
    }
    return segment_index;
}
//# sourceMappingURL=trajectory.js.map