using System.Reflection;
using EFT;
using HarmonyLib;
using SPT.Reflection.Patching;

namespace SmartAction.Patch;

/// <summary>
/// Lets you sprint while using meds / healing legs.
///
/// Vanilla MovementContext.CanSprint (EFT 0.16.9.0.40087):
///     if (PhysicalConditionIs(SprintDisabled))  return false;
///     if (PhysicalConditionIs(UsingMeds))       return false;   // lifted here
///     if (PhysicalConditionIs(HealingLegs))     return false;   // lifted here
///     if (PhysicalConditionIs(OnPainkillers))   return true;
///     if (PhysicalConditionIs(RightLegDamaged)) return false;
///     if (PhysicalConditionIs(LeftLegDamaged))  return false;
///     return true;
///
/// Upstream SmartAction used a prefix that returned false outright, suppressing the original
/// getter for every MovementContext in the raid. That is hard-incompatible with any other mod
/// touching sprint or stamina. This lifts exactly the two med-related blocks and replays the
/// rest of vanilla's chain, so leg damage and SprintDisabled keep their normal meaning.
/// </summary>
public class CanSprintPatch : ModulePatch
{
    protected override MethodBase GetTargetMethod()
    {
        return AccessTools.PropertyGetter(typeof(MovementContext), nameof(MovementContext.CanSprint));
    }

    [PatchPostfix]
    private static void Postfix(MovementContext __instance, ref bool __result)
    {
        if (__result) return;

        if (!MovementPatchUtil.IsLocalPlayer(__instance)) return;

        // Not ours to override — this is a deliberate game/quest/effect lockout.
        if (__instance.PhysicalConditionIs(EPhysicalCondition.SprintDisabled))
        {
            if (Diagnostics.Enabled) Diagnostics.SprintHeldBySprintDisabled++;
            return;
        }

        // Only intervene when meds or leg-healing is what blocked us.
        var blockedByMeds = __instance.PhysicalConditionIs(EPhysicalCondition.UsingMeds)
                            || __instance.PhysicalConditionIs(EPhysicalCondition.HealingLegs);
        if (!blockedByMeds) return;

        // Replay the remainder of vanilla's chain so a broken leg still stops you.
        if (__instance.PhysicalConditionIs(EPhysicalCondition.OnPainkillers))
        {
            __result = true;
            if (Diagnostics.Enabled)
            {
                Diagnostics.SprintLifted++;
                Diagnostics.OnceSprintLifted();
            }
            return;
        }

        if (__instance.PhysicalConditionIs(EPhysicalCondition.RightLegDamaged)
            || __instance.PhysicalConditionIs(EPhysicalCondition.LeftLegDamaged))
        {
            if (Diagnostics.Enabled)
            {
                Diagnostics.SprintHeldByLeg++;
                Diagnostics.OnceSprintHeldByLeg();
            }
            return;
        }

        __result = true;

        if (Diagnostics.Enabled)
        {
            Diagnostics.SprintLifted++;
            Diagnostics.OnceSprintLifted();
        }
    }
}
