import { CSSProperties, ReactElement, useCallback, useEffect, useRef } from "react"
import { add, angle, Pos, relativeTo, size } from "./Pos"

export interface BendableArrowProps {
    basePos: Pos
    startPos: Pos
    endPos: Pos

    startRadius?: number
    endRadius?: number


    style?: ArrowStyle
}

export interface ArrowStyle {
    width?: number,
    head?: () => ReactElement,
    tail?: () => ReactElement,
}


const ArrowStyleDefaults = {
    width: 4
}

function constraintInCircle(pos: Pos, from: Pos, radius: number): Pos {
    const theta = angle(pos, from)

    return {
        x: pos.x - Math.sin(theta) * radius,
        y: pos.y - Math.cos(theta) * radius
    }
}

export default function BendableArrow({ basePos, startPos, endPos, style, startRadius = 0, endRadius = 0 }: BendableArrowProps) {
    const svgRef = useRef<SVGSVGElement>(null)

    const pathRef = useRef<SVGPathElement>(null);

    const styleWidth = style?.width ?? ArrowStyleDefaults.width


    const update = () => {
        const startRelative = relativeTo(startPos, basePos)
        const endRelative = relativeTo(endPos, basePos)

        const tailPos = constraintInCircle(startRelative, endRelative, startRadius)
        const headPos = constraintInCircle(endRelative, startRelative, endRadius)


        // the width and height of the arrow svg
        const svgBoxBounds = size(startPos, endPos)

        const left = Math.min(tailPos.x, headPos.x)
        const top = Math.min(tailPos.y, headPos.y)


        const svgStyle: CSSProperties = {
            width: `${svgBoxBounds.x}px`,
            height: `${svgBoxBounds.y}px`,

            left: `${left}px`,
            top: `${top}px`,
        }


        const d = `M${tailPos.x - left} ${tailPos.y - top} L${headPos.x - left} ${headPos.y - top}`
        pathRef.current!.setAttribute("d", d)

        Object.assign(svgRef.current!.style, svgStyle)
    }

    useEffect(() => {
        //update on resize
        window.addEventListener('resize', update)

        return () => window.removeEventListener('resize', update)
    }, [svgRef, basePos, startPos, endPos])
    //update on position changes
    useEffect(update, [svgRef, basePos, startPos, endPos])

    return (
        <svg ref={svgRef} style={{
            overflow: "visible",
            position: "absolute",
        }}>
            <path
                ref={pathRef}
                stroke={"#000"}
                strokeWidth={styleWidth} />
        </svg>
    )
}
