﻿using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
using Verse.AI;

namespace rjw.RMB
{
	/// <summary>
	/// Generator of RMB categories for bestiality
	/// </summary>
	static class RMB_Bestiality
	{
		/// <summary>
		/// Add bestiality and reverse bestiality options to <paramref name="opts"/>
		/// </summary>
		/// <param name="pawn">Selected pawn</param>
		/// <param name="opts">List of RMB options</param>
		/// <param name="target">Target of the right click</param>
		public static void AddFloatMenuOptions(Pawn pawn, List<FloatMenuOption> opts, LocalTargetInfo target)
		{
			AcceptanceReport canCreateEntries = DoBasicChecks(pawn, target.Pawn);

			if (!canCreateEntries)
			{
				if (RJWSettings.DevMode && !canCreateEntries.Reason.NullOrEmpty())
					opts.Add(new FloatMenuOption(canCreateEntries.Reason, null));

				return;
			}

			canCreateEntries = DoChecks(pawn, target.Pawn);

			if (!canCreateEntries)
			{
				opts.Add(new FloatMenuOption("RJW_RMB_Bestiality".Translate(target.Pawn) + ": " + canCreateEntries.Reason, null));
				return;
			}

			FloatMenuOption opt = GenerateCategoryOption(pawn, target);
			if (opt != null)
				opts.Add(opt);

			opt = GenerateCategoryOption(pawn, target, true);
			if (opt != null)
				opts.Add(opt);
		}

		/// <summary>
		/// Check for the things that should be obvious to the player or does not change for particular pawns.
		/// </summary>
		/// <returns>
		/// AcceptanceReport. Reason is an untranslated string and should only be shown in the DevMode
		/// </returns>
		private static AcceptanceReport DoBasicChecks(Pawn pawn, Pawn target)
		{
			if (!RJWSettings.bestiality_enabled)
			{
				return "No bestiality: Disabled by the mod settings";
			}

			if (target.Downed)
			{
				return "No bestiality: Target is downed";
			}

			if (target.HostileTo(pawn))
			{
				return "No bestiality: Target is hostile";
			}

			if (!xxx.can_be_fucked(target) && !xxx.can_fuck(target))
			{
				return "No bestiality: Target can't have sex";
			}

			if (target.Faction != pawn.Faction)
			{
				return "No bestiality: Target must belong to pawn's faction";
			}

			return true;
		}

		/// <summary>
		/// Check for the things that can change for particular pawns.
		/// </summary>
		/// <returns>
		/// AcceptanceReport. Reason is a translated string and should not be null.
		/// </returns>
		private static AcceptanceReport DoChecks(Pawn pawn, Pawn target)
		{
			if (!pawn.IsDesignatedHero() && !pawn.IsHeroOwner())
			{
				int opinionOf = pawn.relations.OpinionOf(target);
				if (opinionOf < RJWHookupSettings.MinimumRelationshipToHookup)
				{
					if (!(opinionOf > 0 && xxx.is_nympho(pawn)))
					{
						return "RJW_RMB_ReasonLowOpinionOfTarget".Translate();
					}
				}
				if (SexAppraiser.would_fuck(pawn, target) < 0.1f)
				{
					return "RJW_RMB_ReasonUnappealingTarget".Translate();
				}
			}

			if ((pawn.ownership.OwnedBed == null) && (target.ownership.OwnedBed == null))
			{
				return "RJW_RMB_ReasonNeedBed".Translate();
			}

			if ((!pawn.CanReach(target.ownership.OwnedBed, PathEndMode.OnCell, Danger.Some)) && (pawn.ownership.OwnedBed == null))
			{
				return "RJW_RMB_ReasonCantReachBed".Translate();
			}

			if  ((!target.CanReach(pawn.ownership.OwnedBed, PathEndMode.OnCell, Danger.Some)) && (target.ownership.OwnedBed == null))
			{
				return "RJW_RMB_ReasonCantReachBed".Translate();
			}

			return true;
		}

		/// <summary>
		/// Generate one FloatMenuOption
		/// </summary>
		/// <param name="pawn"></param>
		/// <param name="target"></param>
		/// <param name="reverse"></param>
		/// <returns>Category-level item that opens a sub-menu on click</returns>
		private static FloatMenuOption GenerateCategoryOption(Pawn pawn, LocalTargetInfo target, bool reverse = false)
		{
			string text = null;

			if (reverse)
			{
				text = "RJW_RMB_Bestiality_Reverse".Translate(target.Pawn);
			}
			else
			{
				text = "RJW_RMB_Bestiality".Translate(target.Pawn);
			}

			return FloatMenuUtility.DecoratePrioritizedTask(new FloatMenuOption(text, delegate ()
			{
				JobDef job = xxx.bestialityForFemale;
				var validinteractions = RMB_Menu.GenerateNonSoloSexRoleOptions(pawn, target, job, false, reverse);
				if (validinteractions.Any())
					FloatMenuUtility.MakeMenu(validinteractions, (FloatMenuOption opt) => opt.Label, (FloatMenuOption opt) => opt.action);
				else
					Messages.Message("No valid interactions found for " + text, MessageTypeDefOf.RejectInput, false);
			}, MenuOptionPriority.High), pawn, target);
		}
	}
}