import "../../style/basket_court.css"
import {CourtBall} from "./CourtBall";


import {ReactElement, RefObject, useCallback, useState,} from "react"
import CourtPlayer from "./CourtPlayer"
import {Player} from "../../tactic/Player"
import {Action, MovementActionKind} from "../../tactic/Action"
import RemoveAction from "../actions/RemoveAction"
import ArrowAction from "../actions/ArrowAction"


import BendableArrow, {Segment} from "../arrows/BendableArrow"
import {middlePos, NULL_POS, Pos} from "../arrows/Pos"
import BallAction from "../actions/BallAction";
import {CourtObject} from "../../tactic/CourtObjects";

export interface BasketCourtProps {
    players: Player[]
    actions: Action[]
    objects: CourtObject[]
    renderAction: (a: Action, key: number) => ReactElement
    setActions: (f: (a: Action[]) => Action[]) => void
    onPlayerRemove: (p: Player) => void
    onPlayerChange: (p: Player) => void

    onBallRemove: () => void

    onBallMoved: (ball: DOMRect) => void

    courtImage: string
    courtRef: RefObject<HTMLDivElement>
}

export function BasketCourt({
                                objects,
                                onBallMoved,
                                onBallRemove,
                                players,
                                actions,
                                renderAction,
                                setActions,
                                onPlayerRemove,
                                onPlayerChange,
                                courtImage,
                                courtRef,
                            }: BasketCourtProps) {

    function bindArrowToPlayer(originRef: HTMLElement, arrowHead: DOMRect) {
        for (const player of players) {
            if (player.id == originRef.id) {
                continue
            }

            const playerBounds = document
                .getElementById(player.id)!
                .getBoundingClientRect()

            if (
                !(
                    playerBounds.top > arrowHead.bottom ||
                    playerBounds.right < arrowHead.left ||
                    playerBounds.bottom < arrowHead.top ||
                    playerBounds.left > arrowHead.right
                )
            ) {
                const targetPos = document.getElementById(player.id)!.getBoundingClientRect()
                const action: Action = {
                    fromPlayerId: originRef.id,
                    toPlayerId: player.id,
                    type: MovementActionKind.SCREEN,
                    moveFrom: middlePos(originRef.getBoundingClientRect()),
                    segments: [{next: middlePos(targetPos)}],
                }
                setActions((actions) => [...actions, action])
            }
        }
    }

    const [previewArrowOriginPos, setPreviewArrowOriginPos] =
        useState<Pos>(NULL_POS)
    const [isPreviewArrowEnabled, setPreviewArrowEnabled] = useState(false)

    const [previewArrowEdges, setPreviewArrowEdges] = useState<Segment[]>([])

    const updateActionsRelatedTo = useCallback((player: Player) => {
        const newPos = middlePos(document.getElementById(player.id)!.getBoundingClientRect())
        setActions(actions => actions.map(a => {
            if (a.fromPlayerId == player.id) {
                return {...a, moveFrom: newPos}
            }

            if (a.toPlayerId == player.id) {
                const segments = a.segments.toSpliced(a.segments.length - 1, 1, {
                    ...a.segments[a.segments.length - 1],
                    next: newPos
                })
                return {...a, segments}
            }

            return a
        }))
    }, [])

    return (
        <div id="court-container" ref={courtRef} style={{position: "relative"}}>
            <img src={courtImage} alt={"court"} id="court-svg"/>

            {actions.map((action, idx) => renderAction(action, idx))}

            {players.map((player) => (
                <CourtPlayer
                    key={player.id}
                    player={player}
                    onDrag={() => updateActionsRelatedTo(player)}
                    onChange={onPlayerChange}
                    onRemove={() => onPlayerRemove(player)}
                    parentRef={courtRef}
                    availableActions={(pieceRef) => [
                        <RemoveAction
                            key={1}
                            onRemove={() => onPlayerRemove(player)}
                        />,
                        <ArrowAction
                            key={2}
                            onHeadMoved={(headPos) =>
                                setPreviewArrowEdges([
                                    {next: middlePos(headPos)},
                                ])
                            }
                            onHeadPicked={(headPos) => {
                                setPreviewArrowOriginPos(
                                    middlePos(pieceRef.getBoundingClientRect()),
                                )
                                setPreviewArrowEdges([
                                    {next: middlePos(headPos)},
                                ])
                                setPreviewArrowEnabled(true)
                            }}
                            onHeadDropped={(headRect) => {
                                bindArrowToPlayer(pieceRef, headRect)
                                setPreviewArrowEnabled(false)
                            }}
                        />,
                        player.hasBall && <BallAction key={3} onDrop={ref => onBallMoved(ref.getBoundingClientRect())}/>
                    ]}
                />
            ))}

            {objects.map((object) => {
                if (object.type == "ball") {
                    return (
                        <CourtBall
                            onMoved={onBallMoved}
                            ball={object}
                            onRemove={onBallRemove}
                            key="ball"
                        />
                    )
                }
                throw new Error("unknown court object", object.type)
            })}

            {isPreviewArrowEnabled && (
                <BendableArrow
                    startPos={previewArrowOriginPos}
                    segments={previewArrowEdges}
                    //do nothing on change, not really possible as it's a preview arrow
                    onSegmentsChanges={() => {}}
                    endRadius={17}
                    startRadius={26}
                />
            )}
        </div>
    )
}
