using System;
using System.Collections.Generic;
using System.Linq;
using Verse;
using RimWorld;
using HarmonyLib;

namespace SCE.Patches
{
    // Register any new engagements with a RitualObligationTrigger_LewdWedding if available.
    // It's necessary to patch here instead of PawnRelationWorker_Fiance.OnRelationCreated as that
    // gets called before the relation is instantiated
    [HarmonyPatch(typeof(Pawn_RelationsTracker))]
    [HarmonyPatch("AddDirectRelation")]
    public class NotifyRitualObligationTrigger
    {
        // Record the length of the relation list immediately beforehand so we can check that a relation was actually added
        [HarmonyPriority(Priority.VeryLow)]
        public static void Prefix(Pawn_RelationsTracker __instance, ref int __state)
        {
            __state = __instance.DirectRelations.Count;
        }

        [HarmonyPriority(Priority.VeryHigh)]
        public static void Postfix(Pawn_RelationsTracker __instance, Pawn ___pawn, PawnRelationDef def, Pawn otherPawn, int __state)
        {
            if (def != PawnRelationDefOf.Fiance)
            {
                return;
            }

            // Player tried to add a duplicate relation via dev mode, our prefix, etc
            // This condition can be false if our prefix was cancelled by another patch, in which case we'll just trust that
            // it was at least a sane one.
            if (__state == __instance.DirectRelations.Count)
            {
                return;
            }

            var weddingPrecept = (Precept_Ritual) (___pawn.Ideo?.GetPrecept(SCEPreceptDefOf.LewdWedding)
                                     ?? otherPawn.Ideo?.GetPrecept(SCEPreceptDefOf.LewdWedding));

            if (weddingPrecept == null)
            {
                return;
            }

            // The engagement should be at the end of the list as it's only just been added, so unless another extreme-priority
            // patch does something weird, we won't need to search through the whole thing
            DirectPawnRelation engagement;
            if (__state != 0 && __instance.DirectRelations.Count == __state + 1)
            {
                engagement = __instance.DirectRelations[__state];
            }
            else
            {
                engagement = __instance.GetDirectRelation(PawnRelationDefOf.Fiance, otherPawn);
            }

            foreach (var trigger in weddingPrecept.obligationTriggers)
            {
                if (trigger is RitualObligationTrigger_LewdWedding weddingTrigger)
                {
                    weddingTrigger.Notify_PawnEngaged(___pawn, engagement);
                }
            }
        }
    }

    // Prevent the vanilla gathering if either pawn's ideo requires a ritual instead.
    [HarmonyPatch(typeof(VoluntarilyJoinableLordsStarter), nameof(VoluntarilyJoinableLordsStarter.TryStartMarriageCeremony))]
    public class PreventGathering
    {
        public static bool Prefix(Pawn firstFiance, Pawn secondFiance, ref bool __result)
        {
            if ((firstFiance.Ideo?.HasPrecept(SCEPreceptDefOf.LewdWedding) ?? false) || 
                (secondFiance.Ideo?.HasPrecept(SCEPreceptDefOf.LewdWedding) ?? false))
            {
                __result = false;
                return false;
            }
            return true;
        }
    }

    // Remove the RitualObligation associated with these pawns' engagement and de-register with the ObligationTrigger
    [HarmonyPatch(typeof(Pawn_RelationsTracker), nameof(Pawn_RelationsTracker.TryRemoveDirectRelation))]
    public class OnEngagementEnd
    {
        public static void Postfix(Pawn ___pawn, PawnRelationDef def, Pawn otherPawn, bool __result)
        {
            if (!__result || def != PawnRelationDefOf.Fiance)
                return;

            var weddingPrecept = (Precept_Ritual) ___pawn.Ideo?.GetPrecept(SCEPreceptDefOf.LewdWedding);
            if (weddingPrecept != null)
            {
                EndEngagement(weddingPrecept, ___pawn, otherPawn);
            }

            if (___pawn.Ideo != otherPawn.Ideo)
            {
                weddingPrecept = (Precept_Ritual) otherPawn.Ideo?.GetPrecept(SCEPreceptDefOf.LewdWedding);
                if (weddingPrecept != null)
                {
                    EndEngagement(weddingPrecept, ___pawn, otherPawn);
                }
            }
        }

        private static void EndEngagement(Precept_Ritual wedding, Pawn pawn, Pawn otherPawn)
        {
            if (wedding.obligationTriggers == null)
            {
                return;
            }   

            foreach (var weddingTrigger in wedding.obligationTriggers.OfType<RitualObligationTrigger_LewdWedding>())
            {
                weddingTrigger.Notify_EngagementEnded(pawn, otherPawn);
            }
        }
    }
}