/**
 * Generate a straight-line path through all points.
 */
const generateLinearPath = (points) => {
    if (points.length === 0)
        return '';
    if (points.length === 1)
        return `M ${points[0].x} ${points[0].y}`;
    let path = `M ${points[0].x} ${points[0].y}`;
    for (let i = 1; i < points.length; i++) {
        path += ` L ${points[i].x} ${points[i].y}`;
    }
    return path;
};
/**
 * Generate a step path (step at midpoint between points).
 */
const generateStepPath = (points) => {
    if (points.length === 0)
        return '';
    if (points.length === 1)
        return `M ${points[0].x} ${points[0].y}`;
    let path = `M ${points[0].x} ${points[0].y}`;
    for (let i = 1; i < points.length; i++) {
        const prev = points[i - 1];
        const curr = points[i];
        const midX = prev.x + (curr.x - prev.x) / 2;
        path += ` L ${midX} ${prev.y} L ${midX} ${curr.y} L ${curr.x} ${curr.y}`;
    }
    return path;
};
/**
 * Generate a step-before path (vertical first, then horizontal).
 */
const generateStepBeforePath = (points) => {
    if (points.length === 0)
        return '';
    if (points.length === 1)
        return `M ${points[0].x} ${points[0].y}`;
    let path = `M ${points[0].x} ${points[0].y}`;
    for (let i = 1; i < points.length; i++) {
        const prev = points[i - 1];
        const curr = points[i];
        path += ` L ${prev.x} ${curr.y} L ${curr.x} ${curr.y}`;
    }
    return path;
};
/**
 * Generate a step-after path (horizontal first, then vertical).
 */
const generateStepAfterPath = (points) => {
    if (points.length === 0)
        return '';
    if (points.length === 1)
        return `M ${points[0].x} ${points[0].y}`;
    let path = `M ${points[0].x} ${points[0].y}`;
    for (let i = 1; i < points.length; i++) {
        const curr = points[i];
        const prev = points[i - 1];
        path += ` L ${curr.x} ${prev.y} L ${curr.x} ${curr.y}`;
    }
    return path;
};
/**
 * Fritsch-Carlson monotone cubic interpolation.
 *
 * Produces straight lines during consistent trends and smooth curves only
 * at inflection points (direction changes). No overshooting past data bounds.
 *
 * Algorithm: https://en.wikipedia.org/wiki/Monotone_cubic_interpolation
 * Same approach used by D3.js (curveMonotoneX), Recharts, and Chart.js.
 */
const generateMonotonePath = (points) => {
    const n = points.length;
    if (n === 0)
        return '';
    if (n === 1)
        return `M ${points[0].x} ${points[0].y}`;
    if (n === 2) {
        return `M ${points[0].x} ${points[0].y} L ${points[1].x} ${points[1].y}`;
    }
    // Step 1: Compute secant slopes between consecutive points
    const delta = new Array(n - 1);
    const dx = new Array(n - 1);
    for (let k = 0; k < n - 1; k++) {
        dx[k] = points[k + 1].x - points[k].x;
        delta[k] = dx[k] === 0 ? 0 : (points[k + 1].y - points[k].y) / dx[k];
    }
    // Step 2: Initialize tangent slopes
    const m = new Array(n);
    m[0] = delta[0];
    m[n - 1] = delta[n - 2];
    for (let k = 1; k < n - 1; k++) {
        if (delta[k - 1] * delta[k] <= 0) {
            // Sign change or zero — flat tangent preserves monotonicity
            m[k] = 0;
        }
        else {
            m[k] = (delta[k - 1] + delta[k]) / 2;
        }
    }
    // Step 3: Enforce Fritsch-Carlson monotonicity constraints
    for (let k = 0; k < n - 1; k++) {
        if (delta[k] === 0) {
            // Flat segment: tangents at both endpoints must be zero
            m[k] = 0;
            m[k + 1] = 0;
        }
        else {
            const alpha = m[k] / delta[k];
            const beta = m[k + 1] / delta[k];
            const s = alpha * alpha + beta * beta;
            if (s > 9) {
                // Rescale to keep the curve within bounds
                const tau = 3 / Math.sqrt(s);
                m[k] = tau * alpha * delta[k];
                m[k + 1] = tau * beta * delta[k];
            }
        }
    }
    // Step 4: Build SVG path using Hermite-to-Bezier conversion
    let path = `M ${points[0].x} ${points[0].y}`;
    for (let k = 0; k < n - 1; k++) {
        const segDx = dx[k];
        const cp1x = points[k].x + segDx / 3;
        const cp1y = points[k].y + (m[k] * segDx) / 3;
        const cp2x = points[k + 1].x - segDx / 3;
        const cp2y = points[k + 1].y - (m[k + 1] * segDx) / 3;
        path += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${points[k + 1].x} ${points[k + 1].y}`;
    }
    return path;
};
/**
 * Router function that dispatches to the correct path generator based on curve type.
 */
const generateCurvePath = (points, curveType = 'monotone') => {
    if (points.length === 0)
        return '';
    if (points.length === 1)
        return `M ${points[0].x} ${points[0].y}`;
    switch (curveType) {
        case 'monotone':
            return generateMonotonePath(points);
        case 'step':
            return generateStepPath(points);
        case 'stepBefore':
            return generateStepBeforePath(points);
        case 'stepAfter':
            return generateStepAfterPath(points);
        case 'linear':
        default:
            return generateLinearPath(points);
    }
};

export { generateCurvePath, generateLinearPath, generateMonotonePath, generateStepAfterPath, generateStepBeforePath, generateStepPath };
