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 extends CourtPlayerProps {
    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>
    )
}