package com.ygames.ysoccer.match;

import com.badlogic.gdx.math.Vector3;
import com.ygames.ysoccer.framework.EMath;

import static com.ygames.ysoccer.match.PlayerFsm.Id.STATE_STAND_RUN;

class PlayerStateStandRun extends PlayerState {

    PlayerStateStandRun(PlayerFsm fsm) {
        super(STATE_STAND_RUN, fsm);
    }

    @Override
    void doActions() {
        super.doActions();

        if (ball.owner != player) {
            player.getPossession();
        }

        // ball control
        if ((ball.owner == player) && (ball.z < Const.PLAYER_H)) {

            // ball-player angle difference
            float signedAngleDiff = EMath.signedAngleDiff(player.ballAngle, player.a);

            float controlDistance = player.skills.control >= Const.MAX_BALL_CONTROL_SKILL
                ? Const.MAX_CONTROL_KEEP_DISTANCE
                : Const.BALL_CONTROL_DISTANCE;
            if (player.ballDistance < controlDistance) {
                float control = Const.ballControl(player.skills.control);

                // Control slice
                // lowest ball control skill: +/- 70 degrees
                // highest ball control skill: +/- 91 degrees
                float slice = 70 + 3 * control;

                // just ahead of feet: push forward
                if (Math.abs(signedAngleDiff) <= slice && player.ballDistance > 3.5f) {
                    // Control efficacy
                    // lowest ball control skill: 1 + 0.060f * player.v
                    // highest ball control skill: 1 + 0.032f * player.v
                    float m = 1 + (0.06f - 0.004f * control);
                    ball.v = Math.max(ball.v, (m * ((player.ballDistance < controlDistance) ? 1 : 0)) * player.v);

                    // angle correction
                    if (Math.abs(signedAngleDiff) > 22.5) {
                        ball.a = player.a - signedAngleDiff / 2f;
                    } else {
                        ball.a = player.a;
                    }
                }

                // too back: push fast forward
                else {
                    if (player.v > 0) {
                        ball.v = Math.max(ball.v, 1.2f * player.v);
                        ball.a = player.a;
                    }
                }
            }
        }

        // movement
        if (player.inputDevice.value) {
            player.v = player.speed * (1 - 0.1f * ((player == ball.owner) ? 1 : 0));
            player.a = player.inputDevice.angle;
        } else {
            player.v = 0;
        }

        player.animationStandRun();
    }

    @Override
    State checkConditions() {
        if ((player.role == Player.Role.GOALKEEPER)
                && (player == player.team.lineup.get(0))
                && (player.team.near1 != player)
                && (player.inputDevice == player.ai)) {
            return fsm.stateKeeperPositioning;
        }

        // B: shoot with ball, head high loose balls, slide tackle without ball.
        if (player.inputDevice != player.ai && player.inputDevice.fire2Down()) {
            if (ball.owner == player || canKickLooseBall()) {
                if (player.v > 0 && ball.z < 8) {
                    takeLooseBall();
                    player.prepareKick(Player.KickAction.SHOOT);
                    return fsm.stateKick;
                }
            } else if (canHeadBall()) {
                return fsm.stateHead;
            } else {
                return fsm.stateTackle;
            }
        }

        // A: pass with ball, head high loose balls, ask an AI teammate to pass without ball.
        if (player.inputDevice != player.ai && player.inputDevice.fire1Down()) {
            if (ball.owner == player) {
                if (player.v > 0 && ball.z < 8) {
                    player.prepareKick(Player.KickAction.PASS);
                    return fsm.stateKick;
                }
            } else if (canHeadBall()) {
                return fsm.stateHead;
            } else {
                player.team.requestPassToControlledPlayer(player.inputDevice);
            }
        }

        // AI keeps the old single-button split between pass and shot.
        if (player.inputDevice == player.ai && player.inputDevice.fire1Down()) {
            if (ball.owner == player) {
                if (player.v > 0 && ball.z < 8) {
                    player.prepareAiKick();
                    return fsm.stateKick;
                }
            } else if (player.ballDistance < 120 && player.ballIsApproaching()) {
                Vector3 ballPrediction = ball.prediction[Math.min(player.frameDistance, Const.BALL_PREDICTION - 1)];

                if (ballPrediction.z > 18) {
                    return fsm.stateHead;
                } else if (player.v > 0
                        && player.ballIsInFront()
                        && player.ballDistance > 12) {
                    return fsm.stateTackle;
                }
            }
        }
        return null;
    }

    private boolean canKickLooseBall() {
        return ball.owner == null
            && ball.z < 8
            && player.ballDistance <= Const.LOOSE_BALL_KICK_DISTANCE
            && (player.ballIsInFront() || player.ballDistance <= 12f);
    }

    private void takeLooseBall() {
        if (ball.owner == null) {
            scene.setBallOwner(player);
            ball.v = player.v;
            ball.a = player.a;
        }
    }

    private boolean canHeadBall() {
        if (ball.owner != null || player.ballDistance > 34f) {
            return false;
        }
        Vector3 ballPrediction = ball.prediction[Math.min(player.frameDistance, Const.BALL_PREDICTION - 1)];
        return ball.z > 8f || ballPrediction.z > 8f || isAtHeadHeight(ballPrediction) || isAtHeadHeight(ball.z);
    }

    private boolean isAtHeadHeight(Vector3 ballPrediction) {
        float headZ = player.z + Const.PLAYER_H;
        return Math.abs(ballPrediction.z - headZ) <= (3 * Const.BALL_R);
    }

    private boolean isAtHeadHeight(float ballHeight) {
        float headZ = player.z + Const.PLAYER_H;
        return Math.abs(ballHeight - headZ) <= (3 * Const.BALL_R);
    }

}
