using System.Collections.Generic;
using System.Linq;
using PkmnLib.Dynamic;
using PkmnLib.Dynamic.Libraries;
using PkmnLib.Static;
using PkmnLib.Static.Moves;
using PkmnLib.Static.Utils;

namespace PkmnLib.Plugin.Gen7.Libraries;

public class Gen7MiscLibrary : IMiscLibrary
{
    private readonly IMoveData _struggleData = new MoveDataImpl("struggle", new TypeIdentifier(0),
        MoveCategory.Physical, 50,
        255, 255, MoveTarget.Any, 0,
        new SecondaryEffectImpl(-1, "struggle", new Dictionary<StringKey, object?>()), []);

    /// <inheritdoc />
    public ITurnChoice ReplacementChoice(IPokemon user, byte targetSide, byte targetPosition) =>
        new MoveChoice(user, new LearnedMoveImpl(_struggleData, MoveLearnMethod.Unknown), targetSide,
            targetPosition);

    /// <inheritdoc />
    public TimeOfDay GetTimeOfDay()
    {
        var time = StaticHelpers.GetCurrentDateTime().LocalDateTime;
        var hour = time.Hour;
        return hour switch
        {
            >= 0 and <= 5 => TimeOfDay.Night,
            >= 6 and <= 9 => TimeOfDay.Morning,
            >= 10 and <= 16 => TimeOfDay.Day,
            17 => TimeOfDay.Evening,
            _ => TimeOfDay.Night,
        };
    }

    /// <inheritdoc />
    public bool CanFlee(IBattle battle, IFleeChoice fleeChoice)
    {
        var user = fleeChoice.User;
        var battleData = user.BattleData;
        if (battleData == null)
            return false;
        var opponentSide = battle.Sides[battleData.SideIndex == 0 ? 1 : 0];
        var opponent = opponentSide.Pokemon.FirstOrDefault(x => x is not null);
        if (opponent == null)
            return true;
        
        var userSpeed = user.FlatStats.Speed;
        var opponentSpeed = opponent.FlatStats.Speed;
        // If the player's active Pokémon's Speed is greater than or equal to the wild Pokémon's Speed, fleeing will
        // always succeed
        if (userSpeed >= opponentSpeed)
            return true;
        
        var userSide = battle.Sides[battleData.SideIndex];
        
        userSide.RegisterFleeAttempt();
        var fleeChance = ((userSpeed * 32) / (opponentSpeed / 4) + (30 * userSide.FleeAttempts)) / 256;
        var random = battle.Random.GetInt(0, 100);
        return random < fleeChance;
    }
}