import React, {
    KeyboardEventHandler,
    ReactNode,
    RefObject,
    useCallback,
    useRef,
} from "react"
import "../../style/player.css"
import Draggable from "react-draggable"
import { PlayerPiece } from "./PlayerPiece"
import { BallState, PlayerInfo } from "../../model/tactic/Player"
import { NULL_POS, Pos, ratioWithinBase } from "../../geo/Pos"

export interface CourtPlayerProps {
    playerInfo: PlayerInfo
    className?: string
    availableActions: (ro: HTMLElement) => ReactNode[]
}

export interface EditableCourtPlayerProps extends CourtPlayerProps {
    courtRef: RefObject<HTMLElement>
    onPositionValidated: (newPos: Pos) => void
    onRemove: () => void
}

const MOVE_AREA_SENSIBILITY = 0.001

export const PLAYER_RADIUS_PIXELS = 20

export function CourtPlayer({
    playerInfo,
    className,
    availableActions,
}: CourtPlayerProps) {
    const pieceRef = useRef<HTMLDivElement>(null)

    return courtPlayerPiece({
        playerInfo,
        pieceRef,
        className,
        availableActions: () => availableActions(pieceRef.current!),
    })
}

/**
 * A player that is placed on the court, which can be selected, and moved in the associated bounds
 * */
export function EditableCourtPlayer({
    playerInfo,
    className,
    courtRef,

    onPositionValidated,
    onRemove,
    availableActions,
}: EditableCourtPlayerProps) {
    const pieceRef = useRef<HTMLDivElement>(null)
    const { x, y } = playerInfo.pos

    return (
        <Draggable
            handle=".player-piece"
            nodeRef={pieceRef}
            position={NULL_POS}
            onStop={useCallback(() => {
                const pieceBounds = pieceRef.current!.getBoundingClientRect()
                const parentBounds = courtRef.current!.getBoundingClientRect()

                const pos = ratioWithinBase(pieceBounds, parentBounds)

                if (
                    Math.abs(pos.x - x) >= MOVE_AREA_SENSIBILITY ||
                    Math.abs(pos.y - y) >= MOVE_AREA_SENSIBILITY
                ) {
                    onPositionValidated(pos)
                }
            }, [courtRef, onPositionValidated, x, y])}>
            {courtPlayerPiece({
                playerInfo,
                className,
                pieceRef,
                availableActions: () => availableActions(pieceRef.current!),
                onKeyUp: useCallback(
                    (e: React.KeyboardEvent<HTMLDivElement>) => {
                        if (e.key == "Delete") onRemove()
                    },
                    [onRemove],
                ),
            })}
        </Draggable>
    )
}

interface CourtPlayerPieceProps {
    playerInfo: PlayerInfo
    className?: string
    pieceRef?: RefObject<HTMLDivElement>
    availableActions?: () => ReactNode[]
    onKeyUp?: KeyboardEventHandler<HTMLDivElement>
}

function courtPlayerPiece({
    playerInfo,
    className,
    pieceRef,
    onKeyUp,
    availableActions,
}: CourtPlayerPieceProps) {
    const usesBall = playerInfo.ballState != BallState.NONE
    const { x, y } = playerInfo.pos

    return (
        <div
            ref={pieceRef}
            id={playerInfo.id}
            className={"player " + (className ?? "")}
            style={{
                position: "absolute",
                left: `${x * 100}%`,
                top: `${y * 100}%`,
            }}>
            <div tabIndex={0} className="player-content" onKeyUp={onKeyUp}>
                {availableActions && (
                    <div className="player-actions">{availableActions()}</div>
                )}
                <PlayerPiece
                    team={playerInfo.team}
                    text={playerInfo.role}
                    hasBall={usesBall}
                />
            </div>
        </div>
    )
}
