package jesse.keeblarcraft.AttributeMgr.AttributeNodes.FactionNodes;

import java.util.HashMap;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import jesse.keeblarcraft.AttributeMgr.AttributeNodes.AbstractNode;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerCommandFlightCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerEnteredBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerExitedBaseCallback;
import jesse.keeblarcraft.FactionMgr.Callbacks.PlayerInBaseCallback;
import net.minecraft.entity.player.PlayerAbilities;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.Text;
import net.minecraft.util.ActionResult;

public class FactionFlight extends AbstractNode {
    private final int flightSpeed = 1;
    private ServerPlayerEntity player;
    private float SPEED_SCALAR = 40.0f; // The value to scale this correctly to CREATIVE flight is '20.0f' however faction flight is slower than creative intentionally
    private Boolean canFly = false;
    private Boolean loginInBaseToggle = false; // Covers the unique case if player logs in inside the faction block border; in which case they need flight enabled!
    private Integer leaveTimerMs = 5000;

    @Override
    public String GetNodeTitle() {
        return "faction_flight";
    }

    @Override
    public String GetNodeDescription() {
        return "This is a temporary-unlock value when you are around your factions home base block and it has flight unlocked for members!";
    }

    @Override
    public HashMap<String, List<String>> GetDetails() {
        HashMap<String, List<String>> ret = new HashMap<String, List<String>>();
        ret.put("Faction Flight", List.of("Grants flight when near faction base if faction has it unlocked"));
        return ret;
    }

    public Boolean TurnOnFlight(ServerPlayerEntity player) {
        Boolean isFlying = false;
        PlayerAbilities abilities = player.getAbilities();
        if (canFly && !abilities.allowFlying) {
            abilities.allowFlying = true;
            abilities.setFlySpeed((float) (flightSpeed / SPEED_SCALAR));
            isFlying = true;
            player.sendAbilitiesUpdate();
        }

        return isFlying;
    }

    public Boolean TurnOffFlight(ServerPlayerEntity player) {
        Boolean isFlying = false;
        PlayerAbilities abilities = player.getAbilities();
        if (canFly && abilities.allowFlying) {
            abilities.allowFlying = false;
            abilities.flying = false;
            abilities.setFlySpeed(0);
            isFlying = false;
            player.sendAbilitiesUpdate();
        }

        return isFlying;
    }

    public void ResetPlayer(ServerPlayerEntity player) {
        // Disable flight
        PlayerAbilities abilities = player.getAbilities();
        abilities.flying = false;
        abilities.allowFlying = false;
        abilities.setFlySpeed(0);
        player.sendAbilitiesUpdate();
    }

    @Override
    public void RegisterCallbacks() {
        PlayerEnteredBaseCallback.EVENT.register((player, world, power, factionTier) -> {
            player.sendMessage(Text.of("Faction flight enabled"));
            canFly = true;
            ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;

            // Toggle flight
            TurnOnFlight(serverPlayer);
            return ActionResult.PASS;
        });

        PlayerInBaseCallback.EVENT.register((player, world, power, factionTier) -> {
            // Make sure player can fly while inside the border. We don't ever want to run this more than once!
            if (!canFly && !loginInBaseToggle) {
                player.sendMessage(Text.of("Faction flight enabled"));
                loginInBaseToggle = true;
                canFly = true;
                ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
                TurnOnFlight(serverPlayer);
            }
            return ActionResult.PASS;
        });

        PlayerCommandFlightCallback.EVENT.register((player, world, power, factionTier) -> {
            ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
            Boolean isFlying = TurnOnFlight(serverPlayer);
            // This is a toggle command; so first we get if the player is flying
            PlayerAbilities abilities = player.getAbilities();
            if (abilities.flying) {
                TurnOffFlight((ServerPlayerEntity) player);
            } else {
                TurnOnFlight((ServerPlayerEntity) player);
            }
            System.out.println("abilities.flying: " + abilities.flying);

            if(canFly && isFlying) {
                serverPlayer.sendMessage(Text.of("Flight turned on"));
            } else if (canFly && !isFlying) {
                // Infers toggled off
                serverPlayer.sendMessage(Text.of("Flight turned off"));
            } else {
                // Means player is not in fly-zone
                serverPlayer.sendMessage(Text.of("You can only fly within the bounds of your faction base!"));
            }
            return ActionResult.PASS;
        });

        PlayerExitedBaseCallback.EVENT.register((player, world, power, factionTier) -> {
            Timer timer = new Timer();
            canFly = false;
            player.sendMessage(Text.of("You left the faction's perimeter! Flight will disable in 5 seconds..."));
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    // Cover the edge condition such that we leave the faction base (canFly = false) then
                    // the timer here starts and we come back into the base (canFly = true) - we want a NO-OP here
                    if (!canFly) {
                        player.sendMessage(Text.of("Faction flight disabled"));
                        ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player;
                        ResetPlayer(serverPlayer);
                    }
                }
            }, leaveTimerMs);

            return ActionResult.PASS;
        });
    }

}
