using System;
using Verse;
using Verse.AI;
using Verse.AI.Group;
using RimWorld;
using UnityEngine.Experimental.GlobalIllumination;

namespace SCE
{
    // Because wedding spectators were crowding out the couple and the game ignores spectateDistanceOverride if not using SpectateDutyInCircle
    public class JobGiver_SpectateDutyWedding : JobGiver_SpectateDutySpectateRect
    {
        public int spectateRectMargin = 1;

        public int coupleMargin = 0;

        public override ThinkNode DeepCopy(bool resolve = true)
        {
            var result = (JobGiver_SpectateDutyWedding) base.DeepCopy(resolve);
            result.spectateRectMargin = spectateRectMargin;
            result.coupleMargin = coupleMargin;
            return result;
        }

        protected override bool TryFindSpot(Pawn pawn, PawnDuty duty, out IntVec3 spot)
        {
            LordJob_Ritual ritual = (pawn.GetLord()?.LordJob as LordJob_Ritual);
            Precept_Ritual precept = ritual?.Ritual;

            RitualStage stage = precept.behavior.def.stages[ritual.StageIndex];
            IntVec3 initiatorPos = ritual.PawnPositionForStage(ritual.PawnWithRole("initiator"), stage).cell;
            IntVec3 receiverPos = ritual.PawnPositionForStage(ritual.PawnWithRole("receiver"), stage).cell;

            CellRect spectateRect = duty.spectateRect.ExpandToFit(initiatorPos).ExpandToFit(receiverPos).ExpandedBy(coupleMargin);

            if (duty.spectateRectPreferredSide != SpectateRectSide.None
                    && TryFindSpotOnSides(duty.spectateRectPreferredSide, out spot))
            {
                return true;
            }

            if (TryFindSpotOnSides(duty.spectateRectAllowedSides, out spot))
            {
                return true;
            }
            IntVec3 target = duty.spectateRect.CenterCell;
            if (CellFinder.TryFindRandomReachableCellNearPosition(pawn.Position, target, pawn.MapHeld, 5f, TraverseParms.For(pawn),
                (IntVec3 c) => pawn.CanReserveSittableOrSpot(c), (Region r) => r.Room == target.GetRoom(pawn.MapHeld),
                out spot))
            {
                return true;
            }
            Log.Warning("Failed to find a spectator spot for " + pawn);
            return false;

            bool TryFindSpotOnSides(SpectateRectSide side, out IntVec3 spot)
            {
                return SpectatorCellFinder.TryFindSpectatorCellFor(pawn, spectateRect, pawn.Map, out spot,
                    side, spectateRectMargin, null, precept, RitualUtility.GoodSpectateCellForRitual);
            }
        }
    }
}