using System.Collections.Generic;
using System.Linq;
using Multiplayer.API;
using RimWorld;
using Verse;

namespace rjw;

public class HediffComp_Ovipositor : HediffComp
{
	public IntRange eggInterval;

	private int nextEggTick;

	private static HediffDef_InsectEgg UnknownEgg = DefDatabase<HediffDef_InsectEgg>.GetNamed("RJW_UnknownEgg");

	public HediffCompProperties_Ovipositor Props => props as HediffCompProperties_Ovipositor;

	public override void CompPostMake()
	{
	    eggInterval = Props.eggIntervalTicks;
	}
	/// <summary>
	/// egg production ticks
	/// </summary>
	public override void CompPostTick(ref float severityAdjustment)
	{
		base.CompPostTick(ref severityAdjustment);

		var thisTick = Find.TickManager.TicksGame;

		if (thisTick >= nextEggTick)
		{
			var def = parent.def as HediffDef_SexPart;
			var pawn = parent.pawn;
			var isPlayerFaction = pawn.Faction?.IsPlayer ?? false; // Colonists/animals/mechs/mutants
			var onHomeMap = pawn.Map?.IsPlayerHome ?? false;

			if (!onHomeMap && !isPlayerFaction && !pawn.IsPrisonerOfColony && !pawn.IsSlaveOfColony)
			{
				return;
			}

			if (pawn.health.capacities.GetLevel(PawnCapacityDefOf.Moving) <= 0.5)
			{
				return;
			}

			float maxEggsSize = pawn.BodySize / 10f;
			if (xxx.has_quirk(pawn, "Incubator"))
			{
				maxEggsSize *= 2;
			}
			if (Genital_Helper.has_ovipositorF(pawn))
			{
				maxEggsSize *= 4;
			}

			float eggedSize = GetCombinedEggSize(pawn);

			if (RJWSettings.DevMode) ModLog.Message($"{xxx.get_pawnname(pawn)} filled with {eggedSize} out of max capacity of {maxEggsSize} eggs.");
			if (eggedSize < maxEggsSize)
			{
				HediffDef_InsectEgg egg;

				if (RJWSettings.DevMode) ModLog.Message($" Trying to find a {pawn.kindDef} egg");
				if (!TryGetEgg(pawn.kindDef.defName, out egg))
				{
					if (RJWSettings.DevMode) ModLog.Message($" No {pawn.kindDef} egg found, defaulting to UnknownEgg");
					egg = UnknownEgg;
				}

				if (RJWSettings.DevMode) ModLog.Message($"I choose you, {egg}!");

				var parentPart = parent.Part;
				if (parentPart != null)
				{
					AddEggs(egg, parentPart, Props.eggCount);
				}
			}

			// Reset for next egg.
			nextEggTick = RandomNextEggTick(thisTick);
		}
	}

	private static float GetCombinedEggSize(Pawn pawn)
	{
		float eggedSize = 0;
		List<Hediff_InsectEgg> ownEggs = new();
		pawn.health.hediffSet.GetHediffs(ref ownEggs);
		foreach (var ownEgg in ownEggs)
		{
			eggedSize += ownEgg.eggssize;
		}

		return eggedSize;
	}

	[SyncMethod]
	private int RandomNextEggTick(int fromTick)
	{
		return fromTick + eggInterval.RandomInRange;
	}

	[SyncMethod]
	private static bool TryGetEgg(string defname, out HediffDef_InsectEgg result)
	{
		var possibleEggs = PossibleEggs(defname);
		return possibleEggs.TryRandomElement(out result);
	}

	public static IEnumerable<HediffDef_InsectEgg> PossibleEggs(string defName)
	{
		if (defName == null)
		{
			return Enumerable.Empty<HediffDef_InsectEgg>();
		}
		return DefDatabase<HediffDef_InsectEgg>.AllDefs.Where(eggDef => eggDef.CanHaveParent(defName));
	}

	public void AddEggs(HediffDef_InsectEgg eggDef, BodyPartRecord bodyPart, FloatRange range)
	{
		float eggScore = range.RandomInRange + 0.5f;

		if (RJWSettings.DevMode)
		{
			ModLog.Message($"Added egg count: {eggScore}, int: {(int)eggScore}");
			ModLog.Message($"Min egg count: {range.min}, int: {(int)range.min}");
			ModLog.Message($"Max egg count: {range.max}, int: {(int)range.max}");
		}

		int eggsToAdd = (int) eggScore;
		for (int i = 0; i < eggsToAdd; i++)
		{
			var addedEgg = parent.pawn.health.AddHediff(eggDef, bodyPart) as Hediff_InsectEgg;
			addedEgg?.InitImplanter(parent.pawn);
		}
	}

	public override void CompExposeData()
	{
		base.CompExposeData();
		Scribe_Values.Look(ref nextEggTick, "nextEggTick");
		Scribe_Values.Look(ref eggInterval, "eggInterval", defaultValue: Props.eggIntervalTicks);
	}
}