using GUI_2;
using HarmonyLib;
using KFCommonUtilityLib.Scripts.Attributes;
using KFCommonUtilityLib.Scripts.StaticManagers;
using KFCommonUtilityLib.Scripts.Utilities;
using System.Collections;
using Unity.Mathematics;

[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(AlternativeData))]
public class ActionModuleAlternative
{
    internal static ItemValue InventorySetItemTemp;

    [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix]
    private bool Prefix_StartHolding(ItemActionData _data, AlternativeData __customData)
    {
        //__customData.Init();
        int prevMode = __customData.mapping.CurMode;
        __customData.UpdateUnlockState(_data.invData.itemValue);
        if (prevMode != __customData.mapping.CurMode && _data.invData.holdingEntity is EntityPlayerLocal player)
        {
            MultiActionManager.FireToggleModeEvent(player, __customData.mapping);
        }
        MultiActionManager.SetMappingForEntity(_data.invData.holdingEntity.entityId, __customData.mapping);
        if (_data.invData.holdingEntity is EntityPlayerLocal)
        {
            MultiActionManager.inputCD = math.max(0.5f, MultiActionManager.inputCD);
            //ThreadManager.StartCoroutine(DelaySetExecutionIndex(_data.invData.holdingEntity, __customData.mapping));
        }
        return true;
    }

    //[MethodTargetPostfix(nameof(ItemActionAttack.StartHolding))]
    //private void Postfix_StartHolding(AlternativeData __customData)
    //{
    //    __customData.UpdateMuzzleTransformOverride();
    //    __customData.OverrideMuzzleTransform(__customData.mapping.CurMode);
    //}

    private static IEnumerator DelaySetExecutionIndex(EntityAlive player, MultiActionMapping mapping)
    {
        yield return null;
        yield return null;
        if (GameManager.Instance.GetGameStateManager().IsGameStarted())
            player?.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, mapping.CurActionIndex);
    }

    [HarmonyPatch(nameof(ItemActionRanged.CancelReload)), MethodTargetPrefix]
    private bool Prefix_CancelReload(ItemActionData _actionData, AlternativeData __customData)
    {
        if (__customData.mapping == null)
            return true;
        int actionIndex = __customData.mapping.CurActionIndex;
        if (ConsoleCmdReloadLog.LogInfo)
            Log.Out($"cancel reload {actionIndex}");
        if (actionIndex == 0)
            return true;
        _actionData.invData.holdingEntity.inventory.holdingItem.Actions[actionIndex].CancelReload(_actionData.invData.holdingEntity.inventory.holdingItemData.actionData[actionIndex]);
        return false;
    }

    [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPrefix]
    private bool Prefix_CancelAction(ItemActionData _actionData, AlternativeData __customData)
    {
        if (__customData.mapping == null)
            return true;
        int actionIndex = __customData.mapping.CurActionIndex;
        if (ConsoleCmdReloadLog.LogInfo)
            Log.Out($"cancel action {actionIndex}");
        if (actionIndex == 0)
            return true;
        _actionData.invData.holdingEntity.inventory.holdingItem.Actions[actionIndex].CancelAction(_actionData.invData.holdingEntity.inventory.holdingItemData.actionData[actionIndex]);
        return false;
    }

    [HarmonyPatch(nameof(ItemAction.IsStatChanged)), MethodTargetPrefix]
    private bool Prefix_IsStatChanged(ref bool __result)
    {
        var mapping = MultiActionManager.GetMappingForEntity(GameManager.Instance.World.GetPrimaryPlayerId());
        __result |= mapping != null && mapping.CheckDisplayMode();
        return false;
    }

    //[MethodTargetPostfix(nameof(ItemActionAttack.StopHolding))]
    //private void Postfix_StopHolding(AlternativeData __customData)
    //{
    //    //moved to harmony patch
    //    //MultiActionManager.SetMappingForEntity(_data.invData.holdingEntity.entityId, null);
    //    __customData.mapping.SaveMeta();
    //}

    //todo: change to action specific property
    [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix]
    private void Postfix_OnModificationChanged(ItemActionData _data, ItemActionAttack __instance, AlternativeData __customData)
    {
        __instance.Properties.ParseString("ToggleActionSound", ref __customData.toggleSound);
        __customData.toggleSound = _data.invData.itemValue.GetPropertyOverrideForAction("ToggleActionSound", __customData.toggleSound, __instance.ActionIndex);
        __customData.mapping.toggleSound = __customData.toggleSound;
    }

    [HarmonyPatch(nameof(ItemAction.SetupRadial)), MethodTargetPrefix]
    private bool Prefix_SetupRadial(XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl)
    {
        var mapping = MultiActionManager.GetMappingForEntity(_epl.entityId);
        if (mapping != null)
        {
            var radialContextItem = new AlternativeRadialContextItem(mapping, _xuiRadialWindow, _epl);
            _xuiRadialWindow.SetCommonData(UIUtils.GetButtonIconForAction(_epl.playerInput.Reload), handleRadialCommand, radialContextItem, radialContextItem.PreSelectedIndex, false, radialValidTest);
        }

        return false;
    }

    private bool radialValidTest(XUiC_Radial _sender, XUiC_Radial.RadialContextAbs _context)
    {
        AlternativeRadialContextItem radialContextItem = _context as AlternativeRadialContextItem;
        if (radialContextItem == null)
        {
            return false;
        }
        EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer;
        return radialContextItem.mapping == MultiActionManager.GetMappingForEntity(entityPlayer.entityId) && radialContextItem.mapping.CurActionIndex == radialContextItem.ActionIndex;
    }

    //redirect reload call to shared meta action, which then sets ItemActionIndex animator param to its action index
    //for example if action 3 share meta with action 0, then ItemActionIndex is set to 0 on reload begin.
    //since event param item action data is set to the shared meta action data, all reload related passive calculation and trigger events goes there.
    private void handleRadialCommand(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context)
    {
        AlternativeRadialContextItem radialContextItem = _context as AlternativeRadialContextItem;
        if (radialContextItem == null)
        {
            return;
        }
        EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer;
        if (radialContextItem.mapping == MultiActionManager.GetMappingForEntity(entityPlayer.entityId) && radialContextItem.mapping.CurActionIndex == radialContextItem.ActionIndex)
        {
            entityPlayer.MinEventContext.ItemActionData = entityPlayer.inventory.holdingItemData.actionData?[radialContextItem.ActionIndex];
            (entityPlayer.inventory.holdingItem.Actions?[radialContextItem.ActionIndex] as ItemActionRanged)?.SwapSelectedAmmo(entityPlayer, _commandIndex);
        }
    }

    public class AlternativeData
    {
        public MultiActionMapping mapping;
        public string toggleSound;
        public ItemInventoryData invData;
        //private bool inited = false;
        private readonly bool[] unlocked = new bool[MultiActionIndice.MAX_ACTION_COUNT];
        //public Transform[] altMuzzleTrans = new Transform[MultiActionIndice.MAX_ACTION_COUNT];
        //public Transform[] altMuzzleTransDBarrel = new Transform[MultiActionIndice.MAX_ACTION_COUNT];

        public AlternativeData(ItemInventoryData invData, int actionIndex, ActionModuleAlternative module)
        {
            this.invData = invData;
            Init();

        }

        //public void UpdateMuzzleTransformOverride()
        //{
        //    for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++)
        //    {
        //        int curActionIndex = mapping.indices.GetActionIndexForMode(i);
        //        if (curActionIndex < 0)
        //        {
        //            break;
        //        }
        //        var rangedData = invData.actionData[curActionIndex] as ItemActionRanged.ItemActionDataRanged;
        //        if (rangedData != null)
        //        {
        //            if (rangedData.IsDoubleBarrel)
        //            {
        //                altMuzzleTrans[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle_L{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle;
        //                altMuzzleTransDBarrel[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle_R{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle2;
        //            }
        //            else
        //            {
        //                altMuzzleTrans[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle;
        //            }
        //        }
        //    }
        //}

        public void Init()
        {
            //if (inited)
            //    return;

            //inited = true;
            MultiActionIndice indices = MultiActionManager.GetActionIndiceForItemID(invData.item.Id);
            mapping = new MultiActionMapping(this, indices, invData.holdingEntity, InventorySetItemTemp, toggleSound, invData.slotIdx, unlocked);
            UpdateUnlockState(InventorySetItemTemp);
        }

        public void UpdateUnlockState(ItemValue itemValue)
        {
            //if (!inited)
            //    return;
            unlocked[0] = true;
            for (int i = 1; i < mapping.ModeCount; i++)
            {
                bool flag = true;
                int actionIndex = mapping.indices.GetActionIndexForMode(i);
                ItemAction action = itemValue.ItemClass.Actions[actionIndex];
                action.Properties.ParseBool("ActionUnlocked", ref flag);
                if (bool.TryParse(itemValue.GetPropertyOverride($"ActionUnlocked_{actionIndex}", flag.ToString()), out bool overrideFlag))
                    flag = overrideFlag;
                unlocked[i] = flag;
            }
            //by the time we check unlock state, ItemValue in inventory slot might not be ready yet
            mapping.SaveMeta(itemValue);
            mapping.CurMode = mapping.CurMode;
            mapping.ReadMeta(itemValue);
        }

        public bool IsActionUnlocked(int actionIndex)
        {
            int mode = mapping.indices.GetModeForAction(actionIndex);
            if (mode >= MultiActionIndice.MAX_ACTION_COUNT || mode < 0)
                return false;
            return unlocked[mode];
        }

//        public void OverrideMuzzleTransform(int mode)
//        {
//            var rangedData = invData.actionData[mapping.indices.GetActionIndexForMode(mode)] as ItemActionRanged.ItemActionDataRanged;
//            if (rangedData != null)
//            {
//                if (rangedData.IsDoubleBarrel)
//                {
//                    rangedData.muzzle = altMuzzleTrans[mode];
//                    rangedData.muzzle2 = altMuzzleTransDBarrel[mode];
//                }
//                else
//                {
//                    rangedData.muzzle = altMuzzleTrans[mode];
//                }
//            }
//#if DEBUG
//            Log.Out($"setting muzzle transform for action {rangedData.indexInEntityOfAction} to {rangedData.muzzle.name}\n{StackTraceUtility.ExtractStackTrace()}");
//#endif
//        }
    }

    //todo: don't setup for every mode, and use reload animation from shared action
    public class AlternativeRadialContextItem : XUiC_Radial.RadialContextAbs
    {
        public MultiActionMapping mapping;

        public int ActionIndex { get; private set; }
        public int PreSelectedIndex { get; private set; }

        public AlternativeRadialContextItem(MultiActionMapping mapping, XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl)
        {
            this.mapping = mapping;
            ActionIndex = mapping.CurActionIndex;
            PreSelectedIndex = mapping.SetupRadial(_xuiRadialWindow, _epl);
        }
    }
}
