using System.Collections.Generic;
using System.Reflection;
using HarmonyLib;
using RimWorld;
using Verse;
using UnityEngine;

namespace CombatExtended;
public class CompUnderBarrel : CompRangedGizmoGiver
{
    public CompProperties_UnderBarrel Props => (CompProperties_UnderBarrel)this.props;

    public CompEquippable _compEq;

    public CompEquippable CompEq
    {
        get
        {
            if (_compEq == null)
            {
                _compEq = this.parent.TryGetComp<CompEquippable>();
            }

            return _compEq;
        }
    }

    public CompAmmoUser _compAmmo;

    public CompAmmoUser CompAmmo
    {
        get
        {
            if (_compAmmo == null)
            {
                _compAmmo = this.parent.TryGetComp<CompAmmoUser>();
            }

            return _compAmmo;
        }
    }

    public CompFireModes _compFireModes;

    public CompFireModes CompFireModes
    {
        get
        {
            if (_compFireModes == null)
            {
                _compFireModes = this.parent.TryGetComp<CompFireModes>();
            }

            return _compFireModes;
        }
    }

    public CompProperties_FireModes _compPropsFireModes;

    public CompProperties_FireModes CompPropsFireModes
    {
        get
        {
            if (_compPropsFireModes == null)
            {
                _compPropsFireModes = this.parent.def.comps.Find(x => x is CompProperties_FireModes) as CompProperties_FireModes;
            }

            return _compPropsFireModes;
        }
    }

    public VerbProperties _defVerbProps;

    public VerbProperties DefVerbProps
    {
        get
        {
            if (_defVerbProps == null)
            {
                _defVerbProps = this.parent.def.Verbs.Find(x => x is VerbPropertiesCE);
            }

            return _defVerbProps;
        }
    }

    public CompProperties_AmmoUser _compPropsAmmo;

    public CompProperties_AmmoUser CompPropsAmmo
    {
        get
        {
            if (_compPropsAmmo == null)
            {
                _compPropsAmmo = (CompProperties_AmmoUser)this.parent.def.comps.Find(x => x is CompProperties_AmmoUser);
            }

            return _compPropsAmmo;
        }
    }

    public bool OneAmmoHolder => Props.oneAmmoHolder;

    public bool requiresReload => Props.requiresReload;

    public AmmoDef mainGunLoadedAmmo;

    public int mainGunMagCount;

    public int previousTryReloadOn = 0;

    public AmmoDef UnderBarrelLoadedAmmo;

    public int UnderBarrelMagCount;

    public bool usingUnderBarrel;

    private FireMode _cachedBarrelFireMode;

    private FireMode _cachedUnderbarrelFireMode;

    private AimMode _cachedBarrelAimMode;

    private AimMode _cachedUnderbarrelAimMode;

    [Compatibility.Multiplayer.SyncMethod]
    public void SwitchToUB()
    {
        if (requiresReload)
        {
            CompAmmo.TryUnload(true);
        }
        if (!OneAmmoHolder)
        {
            mainGunLoadedAmmo = CompAmmo.CurrentAmmo;
            mainGunMagCount = CompAmmo.CurMagCount;
            CompAmmo.CurMagCount = UnderBarrelMagCount;
            CompAmmo.CurrentAmmo = UnderBarrelLoadedAmmo ?? Props.propsUnderBarrel.ammoSet.ammoTypes[0].ammo; //same as AmmoUser's init
            CompAmmo.SelectedAmmo = CompAmmo.CurrentAmmo;
        }


        var currentTryReloadOn = CompAmmo.TryReloadOn;
        CompAmmo.TryReloadOn = previousTryReloadOn;
        previousTryReloadOn = currentTryReloadOn;


        CompAmmo.props = this.Props.propsUnderBarrel;

        CompEq.PrimaryVerb.verbProps = Props.verbPropsUnderBarrel;
        _cachedBarrelFireMode = CompFireModes.CurrentFireMode;
        _cachedBarrelAimMode = CompFireModes.CurrentAimMode;
        CompFireModes.props = this.Props.propsFireModesUnderBarrel;
        if (CompAmmo.Wielder != null)
        {
            CompAmmo.Wielder.TryGetComp<CompInventory>().UpdateInventory();

            if (CompAmmo.Wielder.jobs?.curJob?.def == CE_JobDefOf.ReloadWeapon)
            {
                CompAmmo.Wielder.jobs.EndCurrentJob(Verse.AI.JobCondition.InterruptForced);
            }
        }
        // Setting main verbProp burstShotCount equal to the underBarrel's burstShotCount
        // Ensures that there should be a burstFire option
        // If set to aimedBurstShotCount, will result in warning and no burst fire mode. Only full auto
        CompEq.PrimaryVerb.verbProps.burstShotCount = this.Props.verbPropsUnderBarrel.burstShotCount;
        CompEq.PrimaryVerb.cachedTicksBetweenBurstShots = null;
        usingUnderBarrel = true;
        CompFireModes.InitAvailableFireModes();

        if (CompFireModes.AvailableFireModes.Contains(_cachedUnderbarrelFireMode))
        {
            CompFireModes.CurrentFireMode = _cachedUnderbarrelFireMode;
        }
        if (CompFireModes.AvailableAimModes.Contains(_cachedUnderbarrelAimMode))
        {
            CompFireModes.CurrentAimMode = _cachedUnderbarrelAimMode;
        }

        ClearWeaponCaches(this.parent);

        if (requiresReload)
        {
            CompAmmo.TryStartReload();
        }
    }

    [Compatibility.Multiplayer.SyncMethod]
    public void SwithToB()
    {
        if (requiresReload)
        {
            CompAmmo.TryUnload(true);
        }
        if (!OneAmmoHolder)
        {
            UnderBarrelLoadedAmmo = CompAmmo.CurrentAmmo;
            UnderBarrelMagCount = CompAmmo.CurMagCount;
            CompAmmo.CurMagCount = mainGunMagCount;
            CompAmmo.CurrentAmmo = mainGunLoadedAmmo;
            CompAmmo.SelectedAmmo = CompAmmo.CurrentAmmo;
        }

        CompAmmo.props = CompPropsAmmo;


        var currentTryReloadOn = CompAmmo.TryReloadOn;
        CompAmmo.TryReloadOn = previousTryReloadOn;
        previousTryReloadOn = currentTryReloadOn;


        CompEq.PrimaryVerb.verbProps = DefVerbProps.MemberwiseClone();
        _cachedUnderbarrelFireMode = CompFireModes.CurrentFireMode;
        _cachedUnderbarrelAimMode = CompFireModes.CurrentAimMode;
        CompFireModes.props = CompPropsFireModes;
        if (CompAmmo.Wielder != null)
        {
            CompAmmo.Wielder.TryGetComp<CompInventory>().UpdateInventory();

            if (CompAmmo.Wielder.jobs?.curJob?.def == CE_JobDefOf.ReloadWeapon)
            {
                CompAmmo.Wielder.jobs.EndCurrentJob(Verse.AI.JobCondition.InterruptForced);
            }
        }
        CompEq.PrimaryVerb.verbProps.burstShotCount = DefVerbProps.burstShotCount;
        CompEq.PrimaryVerb.cachedTicksBetweenBurstShots = null;
        usingUnderBarrel = false;
        CompFireModes.InitAvailableFireModes();

        if (CompFireModes.AvailableFireModes.Contains(_cachedBarrelFireMode))
        {
            CompFireModes.CurrentFireMode = _cachedBarrelFireMode;
        }
        if (CompFireModes.AvailableAimModes.Contains(_cachedBarrelAimMode))
        {
            CompFireModes.CurrentAimMode = _cachedBarrelAimMode;
        }

        ClearWeaponCaches(this.parent);

        if (requiresReload)
        {
            CompAmmo.TryStartReload();
        }
    }

    private static void ClearWeaponCaches(Thing thing)
    {
        StatDef magazineStatDef = DefDatabase<StatDef>.GetNamed(CE_StatDefOf.MagazineCapacity.ToString());
        magazineStatDef?.Worker.ClearCacheForThing(thing);
    }

    public override IEnumerable<Gizmo> CompGetGizmosExtra()
    {
        if (Props.propsUnderBarrel != null && (CompEq.Holder?.Faction == Faction.OfPlayer || DebugSettings.godMode))
        {
            if (!usingUnderBarrel)
            {
                yield return new Command_Action
                {

                    defaultLabel = string.IsNullOrEmpty(Props.underBarrelLabel) ? "CE_SwitchAmmmoSetToUnderBarrel".Translate().ToString() : Props.underBarrelLabel,
                    icon = ContentFinder<Texture2D>.Get(string.IsNullOrEmpty(Props.underBarrelIconTexPath) ? "UI/Buttons/Reload" : Props.underBarrelIconTexPath),
                    defaultDesc = "CE_UBGLStats".Translate() +
                    "\n " + "WarmupTime".Translate() + ": " + Props.verbPropsUnderBarrel.warmupTime
                    + "\n " + "Range".Translate() + ": " + Props.verbPropsUnderBarrel.range
                    +
                    (Props.oneAmmoHolder || Props.propsUnderBarrel?.ammoSet?.label != null ? "" :
                     "\n " + "CE_AmmoSet".Translate() + ": " + Props.propsUnderBarrel.ammoSet.label
                    + "\n " + "CE_MagazineSize".Translate() + ": " + Props.propsUnderBarrel.magazineSize
                    )
                    ,
                    action = delegate
                    {
                        SwitchToUB();
                    }
                };
            }
            else
            {
                yield return new Command_Action
                {

                    defaultLabel = string.IsNullOrEmpty(Props.standardLabel) ? "CE_SwitchAmmmoSetToNormalRifle".Translate().ToString() : Props.standardLabel,
                    icon = ContentFinder<Texture2D>.Get(string.IsNullOrEmpty(Props.standardIconTexPath) ? "UI/Buttons/Reload" : Props.standardIconTexPath),
                    action = delegate
                    {
                        SwithToB();
                    }
                };
            }
        }
    }

    public override void Initialize(CompProperties props)
    {
        if (this.parent.def.weaponTags.NullOrEmpty())
        {
            this.parent.def.weaponTags = new List<string>() { "NoSwitch" };
        }
        else if (!this.parent.def.weaponTags.Contains("NoSwitch"))
        {
            this.parent.def.weaponTags.Add("NoSwitch");
        }
        base.Initialize(props);
    }

    public override void PostExposeData()
    {

        if (Scribe.mode == LoadSaveMode.Saving)
        {
            if (usingUnderBarrel)
            {
                UnderBarrelMagCount = CompAmmo.CurMagCount;
                UnderBarrelLoadedAmmo = CompAmmo.CurrentAmmo;
            }
        }
        Scribe_Values.Look(ref usingUnderBarrel, "usingUnderBarrel");
        Scribe_Defs.Look(ref mainGunLoadedAmmo, "mainGunAmmo");
        Scribe_Defs.Look(ref UnderBarrelLoadedAmmo, "UnderBarrelAmmo");
        Scribe_Values.Look(ref mainGunMagCount, "magCountMainGun");
        Scribe_Values.Look(ref UnderBarrelMagCount, "UnderBarrelMagCount");
        Scribe_Values.Look(ref _cachedBarrelFireMode, "cachedBarrelFireMode");
        Scribe_Values.Look(ref _cachedUnderbarrelFireMode, "cachedUnderbarrelFireMode");
        Scribe_Values.Look(ref _cachedBarrelAimMode, "cachedBarrelAimMode");
        Scribe_Values.Look(ref _cachedUnderbarrelAimMode, "cachedUnderbarrelAimMode");
        Scribe_Values.Look(ref previousTryReloadOn, nameof(previousTryReloadOn));
        if (Scribe.mode == LoadSaveMode.PostLoadInit)
        {
            if (usingUnderBarrel)
            {
                if (!OneAmmoHolder)
                {
                    CompAmmo.CurMagCount = UnderBarrelMagCount;
                    CompAmmo.CurrentAmmo = UnderBarrelLoadedAmmo;
                }

                CompAmmo.props = this.Props.propsUnderBarrel;
                CompEq.PrimaryVerb.verbProps = Props.verbPropsUnderBarrel;
                CompFireModes.props = this.Props.propsFireModesUnderBarrel;

                if (CompAmmo.Wielder != null)
                {
                    CompAmmo.Wielder.TryGetComp<CompInventory>().UpdateInventory();
                }
            }
        }
        base.PostExposeData();

    }
}

public class CompProperties_UnderBarrel : CompProperties
{

    public CompProperties_AmmoUser propsUnderBarrel;

    public VerbPropertiesCE verbPropsUnderBarrel;

    public CompProperties_FireModes propsFireModesUnderBarrel;

    public List<string> targetTags;

    public bool targetHighVal;

    public bool oneAmmoHolder = false;

    public bool requiresReload = false;

    [MustTranslate]
    public string underBarrelLabel;

    [MustTranslate]
    public string standardLabel;

    public string underBarrelIconTexPath;

    public string standardIconTexPath;

    public CompProperties_UnderBarrel()
    {
        this.compClass = typeof(CompUnderBarrel);
    }
}
