using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using RimWorld;
using HarmonyLib;
using UnityEngine;
using Verse.AI;
using Verse;
using Verse.Sound;
using yayoShooting;

namespace AdditionalVerb
{

    [StaticConstructorOnStartup]
    public static class AdditionalVerbPatch
    {
        private static readonly Type patchType = typeof(AdditionalVerbPatch);
        static AdditionalVerbPatch()
        {
            Harmony harmonyInstance = new Harmony("com.AdditionalVerb.rimworld.mod");
            harmonyInstance.Patch(AccessTools.Method(typeof(Pawn_EquipmentTracker), "GetGizmos", null, null), null, new HarmonyMethod(patchType, "GetGizmosPostfix", null));

            harmonyInstance.Patch(AccessTools.Method(typeof(Targeter), "BeginTargeting", new Type[] { typeof(ITargetingSource) ,typeof(ITargetingSource)}), new HarmonyMethod(patchType, "BeginTargetingPrefix", null));
            harmonyInstance.Patch(AccessTools.Method(typeof(Targeter), "OrderPawnForceTarget"), null, new HarmonyMethod(patchType, "OrderPawnForceTargetPostfix", null));
            harmonyInstance.Patch(AccessTools.Method(typeof(Targeter), "StopTargeting", null, null), new HarmonyMethod(patchType, "StopTargetingPrefix", null));

            harmonyInstance.Patch(AccessTools.Method(typeof(VerbTracker), "CreateVerbTargetCommand", null, null), new HarmonyMethod(patchType, "CreateVerbTargetCommandPrefix", null));
            harmonyInstance.Patch(AccessTools.Property(typeof(VerbTracker), "PrimaryVerb").GetGetMethod(), new HarmonyMethod(patchType, "PrimaryVerbPrefix", null));

            harmonyInstance.Patch(AccessTools.Method(typeof(VerbProperties), "AdjustedAccuracy", null, null), null, new HarmonyMethod(patchType, "AdjustedAccuracyPostfix", null));

            harmonyInstance.Patch(AccessTools.Method(typeof(TooltipUtility), "ShotCalculationTipString", null, null), new HarmonyMethod(patchType, "ShotCalculationTipStringPrefix", null));
            
        }
        public static Texture2D currentCommandTexture= ContentFinder<Texture2D>.Get("UI/Commands/Select");
        public enum RangeCategory
        {
            Touch,
            Short,
            Medium,
            Long
        }
        public static IEnumerable<Gizmo> GetGizmosPostfix(IEnumerable<Gizmo> __result, Pawn_EquipmentTracker __instance)
        {
			if (!PawnAttackGizmoUtility.CanShowEquipmentGizmos())
			{
				List<ThingWithComps> list = __instance.AllEquipmentListForReading;
				int num;
				for (int i = 0; i < list.Count; i = num + 1)
				{
					ThingWithComps thingWithComps = list[i];
					foreach (Command command in thingWithComps.GetComp<CompEquippable>().GetVerbsCommands())
					{
						if(command is Command_VerbTargetToggle)
						{
							switch (i)
							{
								case 0:
									command.hotKey = KeyBindingDefOf.Misc1;
									break;
								case 1:
									command.hotKey = KeyBindingDefOf.Misc2;
									break;
								case 2:
									command.hotKey = KeyBindingDefOf.Misc3;
									break;
							}
							yield return command;
						}
						
					}
					IEnumerator<Command> enumerator = null;
					num = i;
				}
				list = null;
			}

			int count = 0;
            foreach (Gizmo g in __result)
            {
                if (g is Command)
                {
                    switch (count)
                    {
                        case 0:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc1;
                            break;
                        case 1:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc3;
                            break;
                        case 2:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc4;
                            break;
                        case 3:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc5;
                            break;
                        case 4:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc7;
                            break;
                        case 5:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc8;
                            break;
                        case 6:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc9;
                            break;
                        case 7:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc10;
                            break;
                        case 8:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc11;
                            break;
                        default:
                            ((Command)g).hotKey = KeyBindingDefOf.Misc12;
                            break;
                    }
                }
                yield return g;
                count++;
            }
        }
        public static void BeginTargetingPrefix(ITargetingSource source)
        {
			// 아이콘 클릭
			//Log.Message("A");


			Verb verb = source as Verb;

			if(verb.verbProps is VerbProperties_Custom2)
			{
				return;
			}
            if(verb == null)
            {
                return;
            }
            if (verb.verbTracker != null && verb.verbTracker.directOwner != null && verb.DirectOwner is CompEquippable)
            {
				
				Comp_VerbSaveable comp = ((CompEquippable)verb.DirectOwner).parent.GetComp<Comp_VerbSaveable>();
                if (comp != null)
                {
					if (!(source is Verb_Shoot_Selected))
					{

						comp.currentVerb = verb;

					}
                }
            }
        }
        public static void OrderPawnForceTargetPostfix(Targeter __instance, ITargetingSource targetingSource)
        {
			// 올바른 타겟 지정됨
			//Log.Message("B");
			bool isSelector = false;
			Verb_Shoot_Selected verb_s;
			if (targetingSource is Verb_Shoot_Selected)
			{
				isSelector = true;
				verb_s = targetingSource as Verb_Shoot_Selected;

			}

			Verb verb = targetingSource as Verb;
            if (verb == null)
            {
                return;
            }
            if ( verb.verbTracker != null && verb.verbTracker.directOwner != null && verb.DirectOwner is CompEquippable)
            {
                Comp_VerbSaveable comp = ((CompEquippable)verb.DirectOwner).parent.GetComp<Comp_VerbSaveable>();
                if (comp != null)
                {
                    if (!(Traverse.Create(__instance).Method("CurrentTargetUnderMouse", true).GetValue<LocalTargetInfo>().IsValid))
                    {
                        return;
                    }
					if (!isSelector)
					{
						comp.currentVerb = verb;
					}
				}
            }

        }
        public static bool GetTargetingVerbPrefix(ref Verb __result, Pawn pawn,Verb ___targetingVerb)
        {
            return true;
        }
        public static void StopTargetingPrefix(Verb ___targetingSource)
        {
			// 선택됐던것이 취소되거나 완료될때
			//Log.Message("C");

			Verb verb = ___targetingSource as Verb;
            if (verb == null)
            {
                return;
            }
            if (verb.verbTracker != null && verb.verbTracker.directOwner != null)
            {
                CompEquippable compEquip = verb.DirectOwner as CompEquippable;
                if (compEquip != null)
                {
                    Comp_VerbSaveable compVerbSave = compEquip.parent.GetComp<Comp_VerbSaveable>();
                    if (compVerbSave != null)
                    {
                        compVerbSave.tempVerb = null;
                    }
                }
            }
        }


		// yayo
        public static bool CreateVerbTargetCommandPrefix(ref Command_VerbTarget __result, Thing ownerThing, Verb verb)
        {
			// 틱마다 발동
			//Log.Message("D");
			VerbProperties_Custom2 verbProps2 = verb.verbProps as VerbProperties_Custom2;

			Command_VerbTarget command_VerbTarget = null;
			if (verbProps2 is VerbProperties_Custom2 && !(verb is Verb_Shoot_Selected))
			{
				command_VerbTarget = new Command_VerbTargetToggle();
			}
			else
			{
				command_VerbTarget = new Command_VerbTarget();
			}
			VerbProperties_Custom verbProps = verb.verbProps as VerbProperties_Custom;
			if (verbProps != null)
			{
				command_VerbTarget.defaultDesc = verbProps.desc;
				command_VerbTarget.defaultLabel = verbProps.label;
				Comp_VerbSaveable comp_VerbSaveable = ownerThing.TryGetComp<Comp_VerbSaveable>();
				if (comp_VerbSaveable != null && comp_VerbSaveable.currentVerb == verb)
				{
					command_VerbTarget.icon = currentCommandTexture;
					//command_VerbTarget.icon = verbProps.texture;
				}
				else
				{
					command_VerbTarget.icon = verbProps.texture;
				}
			}
			else
			{
				command_VerbTarget.icon = ownerThing.def.uiIcon;
				command_VerbTarget.defaultDesc = ownerThing.LabelCap + ": " + ownerThing.def.description.CapitalizeFirst();
			}
			command_VerbTarget.iconAngle = ownerThing.def.uiIconAngle;
			command_VerbTarget.iconOffset = ownerThing.def.uiIconOffset;
			command_VerbTarget.tutorTag = "VerbTarget";
			command_VerbTarget.verb = verb;
			if (verb.caster.Faction != Faction.OfPlayer)
			{
				command_VerbTarget.Disable("CannotOrderNonControlled".Translate());
			}
			else if (verb.CasterIsPawn)
			{
				if (verb.CasterPawn.WorkTagIsDisabled(WorkTags.Violent))
				{
					command_VerbTarget.Disable("IsIncapableOfViolence".Translate(verb.CasterPawn.LabelShort, verb.CasterPawn));
				}
				else if (!verb.CasterPawn.drafter.Drafted)
				{
					command_VerbTarget.Disable("IsNotDrafted".Translate(verb.CasterPawn.LabelShort, verb.CasterPawn));
				}
			}


			__result = command_VerbTarget;
			return false;






		}

		public class Command_VerbTargetToggle : Command_VerbTarget
		{
			

			// Token: 0x06001A5B RID: 6747 RVA: 0x000A12C4 File Offset: 0x0009F4C4
			public override void ProcessInput(Event ev)
			{
				if (this.CurActivateSound != null)
				{
					this.CurActivateSound.PlayOneShotOnCamera(null);
				}
				SoundDefOf.Tick_Tiny.PlayOneShotOnCamera(null);

				if (verb.verbProps is VerbProperties_Custom2 && !(verb is Verb_Shoot_Selected))
				{

					Comp_VerbSaveable comp = ((CompEquippable)verb.DirectOwner).parent.GetComp<Comp_VerbSaveable>();
					if (comp != null)
					{
						comp.currentVerb = verb;
					}
				}
				/*
				Targeter targeter = Find.Targeter;
				if (this.verb.CasterIsPawn && targeter.targetingSource != null && targeter.targetingSource.GetVerb.verbProps == this.verb.verbProps)
				{
					Pawn casterPawn = this.verb.CasterPawn;
					if (!targeter.IsPawnTargeting(casterPawn))
					{
						targeter.targetingSourceAdditionalPawns.Add(casterPawn);
						return;
					}
				}
				else
				{
					if (verb.verbProps is VerbProperties_Custom2 && !(verb is Verb_Shoot_Selected))
					{

						Comp_VerbSaveable comp = ((CompEquippable)verb.DirectOwner).parent.GetComp<Comp_VerbSaveable>();
						if (comp != null)
						{
							comp.currentVerb = verb;
						}
					}
					//Find.Targeter.BeginTargeting(this.verb, null);
				}
				*/
			}

			
		}





		public static bool PrimaryVerbPrefix(VerbTracker __instance, ref Verb __result)
        {
			// 틱마다 발동
			//Log.Message("E");

			CompEquippable compEquippable = __instance.directOwner as CompEquippable;
            if(compEquippable !=null)
            {
                Comp_VerbSaveable compVerbSaveable = compEquippable.parent.GetComp<Comp_VerbSaveable>();
                if (compVerbSaveable != null)
                {
                    __result = compVerbSaveable.currentVerb;
                    if (__result != null)
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public static void AdjustedAccuracyPostfix(VerbProperties __instance, ref float __result, RangeCategory cat)
        {
            if (__instance is VerbProperties_Custom)
            {
                switch (cat)
                {
                    case RangeCategory.Touch:
                        __result += __instance.accuracyTouch;
                        break;
                    case RangeCategory.Short:
                        __result += __instance.accuracyShort;
                        break;
                    case RangeCategory.Medium:
                        __result += __instance.accuracyMedium;
                        break;
                    case RangeCategory.Long:
                        __result += __instance.accuracyLong;
                        break;
                    default:
                        throw new InvalidOperationException();
                }
            }
        }

        public static bool ShotCalculationTipStringPrefix(ref string __result, Thing target)
        {
			// 이동 시?
			//Log.Message("F");

			StringBuilder stringBuilder = new StringBuilder();
            if (Find.Selector.SingleSelectedThing != null)
            {
                Thing singleSelectedThing = Find.Selector.SingleSelectedThing;
                Verb verb = null;
                Pawn pawn = singleSelectedThing as Pawn;
                if (pawn != null && pawn != target && pawn.equipment != null && pawn.equipment.Primary != null)
                {
                    Comp_VerbSaveable compsav = pawn.equipment.Primary.GetComp<Comp_VerbSaveable>();
                    if (compsav != null && compsav.tempVerb != null && compsav.tempVerb is Verb_LaunchProjectile)
                    {
                        verb = compsav.tempVerb;
                    }
                    else
                    {
                        verb = pawn.equipment.PrimaryEq.PrimaryVerb;
                    }
                }
                Building_TurretGun building_TurretGun = singleSelectedThing as Building_TurretGun;
                if (building_TurretGun != null && building_TurretGun != target)
                {
                    verb = building_TurretGun.AttackVerb;
                }
                if (verb != null)
                {
                    stringBuilder.Append("ShotBy".Translate(Find.Selector.SingleSelectedThing.LabelShort, Find.Selector.SingleSelectedThing) + ": ");
                    if (verb.CanHitTarget(target))
                    {
                        stringBuilder.Append(ShotReport.HitReportFor(verb.caster, verb, target).GetTextReadout());
                    }
                    else
                    {
                        stringBuilder.AppendLine("CannotHit".Translate());
                    }
                    Pawn pawn2 = target as Pawn;
                    if (pawn2 != null && pawn2.Faction == null && !pawn2.InAggroMentalState)
                    {
                        float manhunterOnDamageChance;
                        if (verb.IsMeleeAttack)
                        {
                            manhunterOnDamageChance = PawnUtility.GetManhunterOnDamageChance(pawn2, 0f, singleSelectedThing);
                        }
                        else
                        {
                            manhunterOnDamageChance = PawnUtility.GetManhunterOnDamageChance(pawn2, singleSelectedThing);
                        }
                        if (manhunterOnDamageChance > 0f)
                        {
                            stringBuilder.AppendLine();
                            stringBuilder.AppendLine(string.Format("{0}: {1}", "ManhunterPerHit".Translate(), manhunterOnDamageChance.ToStringPercent()));
                        }
                    }
                }
            }
            __result = stringBuilder.ToString();
            return false;
        }
    }

    public class Comp_VerbSaveable : ThingComp
    {
        public Verb currentVerb;
        public Verb tempVerb;
        public override void PostSpawnSetup(bool respawningAfterLoad)
        {
            CompEquippable comp = parent.GetComp<CompEquippable>();
            if (currentVerb ==null)
            {
                List<Verb> verbs = comp.AllVerbs;
                for (int i = 0; i < verbs.Count; i++)
                {
                    if (verbs[i].verbProps.isPrimary)
                    {
                        currentVerb = verbs[i];
                        return;
                    }
                }
            }
        }
        public override void PostExposeData()
        {
            base.PostExposeData();
            Scribe_References.Look(ref currentVerb, "currentVerb");
            if(Scribe.mode == LoadSaveMode.PostLoadInit && currentVerb==null)
            {
                CompEquippable comp = parent.GetComp<CompEquippable>();
                List<Verb> verbs = comp.AllVerbs;
                for (int i = 0; i < verbs.Count; i++)
                {
                    if (verbs[i].verbProps.isPrimary)
                    {
                        currentVerb = verbs[i];
                        return;
                    }
                }
            }
        }
    }


    [StaticConstructorOnStartup]
    public class VerbProperties_Custom : VerbProperties
    {
        public string desc;
        public string texPath;
        public Texture2D texture;
        public int maxMagazine;

        public VerbProperties_Custom()
        {
            LongEventHandler.ExecuteWhenFinished(delegate
            {
                if (!texPath.NullOrEmpty())
                {
                    texture = ContentFinder<Texture2D>.Get(texPath);
                }
            });            
        }
        
            
    }
    public class Verb_ShootConsumeable : Verb_Shoot
    {
        public int remainBullet = 0;
        //초기화할때 verbproperties랑remainBullet 동기화해야되

        public override void ExposeData()
        {
            base.ExposeData();
            Scribe_Values.Look(ref remainBullet, "remainBullet");
        }
        protected override bool TryCastShot()
        {
            if (base.TryCastShot())
            {
                if (burstShotsLeft <= 1)
                {
                    SelfConsume();
                }
                return true;
            }
            if (burstShotsLeft < verbProps.burstShotCount)
            {
                SelfConsume();
            }
            return false;
        }

        public override void Notify_EquipmentLost()
        {
            base.Notify_EquipmentLost();
            if (state == VerbState.Bursting && burstShotsLeft < verbProps.burstShotCount)
            {
                SelfConsume();
            }
        }

        private void SelfConsume()
        {
            if(remainBullet>0)
            {
                remainBullet--;
            }
            else
            {
                EquipmentSource.GetComp<CompEquippable>().AllVerbs.Remove(this);
            }
        }
    }
}
