// Pure helpers to compute a point (and its tangent direction) along an arrow's
// path at parameter t in [0, 1]. Mirrors the path-construction rules used by
// Arrow.svelte (linear, quadratic, cubic, Catmull-Rom for 3+ control points).
//
// Used by FlowMarkers and any other consumer that needs to follow the curve.
function lerp(a, b, t) {
    return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
}
function quadratic(p0, p1, p2, t) {
    const a = lerp(p0, p1, t);
    const b = lerp(p1, p2, t);
    return lerp(a, b, t);
}
function quadraticTangent(p0, p1, p2, t) {
    // derivative of quadratic Bezier
    return {
        x: 2 * (1 - t) * (p1.x - p0.x) + 2 * t * (p2.x - p1.x),
        y: 2 * (1 - t) * (p1.y - p0.y) + 2 * t * (p2.y - p1.y)
    };
}
function cubic(p0, p1, p2, p3, t) {
    const a = lerp(p0, p1, t);
    const b = lerp(p1, p2, t);
    const c = lerp(p2, p3, t);
    const d = lerp(a, b, t);
    const e = lerp(b, c, t);
    return lerp(d, e, t);
}
function cubicTangent(p0, p1, p2, p3, t) {
    const u = 1 - t;
    return {
        x: 3 * u * u * (p1.x - p0.x) + 6 * u * t * (p2.x - p1.x) + 3 * t * t * (p3.x - p2.x),
        y: 3 * u * u * (p1.y - p0.y) + 6 * u * t * (p2.y - p1.y) + 3 * t * t * (p3.y - p2.y)
    };
}
/**
 * Sample a single point along an arrow's path at parameter t in [0, 1].
 * Returns x, y and the tangent angle in radians (useful for orienting markers).
 */
export function arrowPointAt(start, end, control, t) {
    t = Math.max(0, Math.min(1, t));
    if (control.length === 0) {
        // straight line
        const p = lerp(start, end, t);
        return { x: p.x, y: p.y, angle: Math.atan2(end.y - start.y, end.x - start.x) };
    }
    if (control.length === 1) {
        const p = quadratic(start, control[0], end, t);
        const tan = quadraticTangent(start, control[0], end, t);
        return { x: p.x, y: p.y, angle: Math.atan2(tan.y, tan.x) };
    }
    if (control.length === 2) {
        const p = cubic(start, control[0], control[1], end, t);
        const tan = cubicTangent(start, control[0], control[1], end, t);
        return { x: p.x, y: p.y, angle: Math.atan2(tan.y, tan.x) };
    }
    // 3+ control points: Catmull-Rom approximated as cubic Bezier segments
    // (matches Arrow.svelte's pathD rendering).
    const pts = [start, ...control, end];
    const segCount = pts.length - 1;
    const segLen = 1 / segCount;
    const segIndex = Math.min(segCount - 1, Math.floor(t / segLen));
    const localT = (t - segIndex * segLen) / segLen;
    const p0 = pts[segIndex === 0 ? 0 : segIndex - 1];
    const p1 = pts[segIndex];
    const p2 = pts[segIndex + 1];
    const p3 = pts[segIndex + 2 < pts.length ? segIndex + 2 : pts.length - 1];
    const c1 = { x: p1.x + (p2.x - p0.x) / 6, y: p1.y + (p2.y - p0.y) / 6 };
    const c2 = { x: p2.x - (p3.x - p1.x) / 6, y: p2.y - (p3.y - p1.y) / 6 };
    const p = cubic(p1, c1, c2, p2, localT);
    const tan = cubicTangent(p1, c1, c2, p2, localT);
    return { x: p.x, y: p.y, angle: Math.atan2(tan.y, tan.x) };
}
