using System.Collections.Generic;
using System.Linq;
using eagle.Notifications.ARNNotifications;
using Net.Eagle0.Eagle.Common;
using Net.Eagle0.Eagle.Views;

namespace eagle.Notifications {
    using static NotificationDetails.SealedValueOneofCase;

    public static class ARNNotificationDispatcher {
        // Used for notifications that we expect to receive, but don't need to handle
        private static readonly ARNNotificationGenerator NoopGenerator = (notification, model) =>
                Enumerable.Empty<Notification>();

        private static readonly Dictionary<
                NotificationDetails.SealedValueOneofCase,
                ARNNotificationGenerator> ArnMap = new() {
            { TruceAmbassadorImprisonedDetails,
              TruceAmbassadorImprisonedDetailsNotificationGenerator.Generator },
            { InvitationAmbassadorImprisonedDetails,
              InvitationAmbassadorImprisonedDetailsNotificationGenerator.Generator },
            { AllianceAmbassadorImprisonedDetails,
              AllianceAmbassadorImprisonedDetailsNotificationGenerator.Generator },
            { BreakAllianceAmbassadorImprisonedDetails,
              BreakAllianceAmbassadorImprisonedDetailsNotificationGenerator.Generator },
            { CapturedHeroExecutedDetails,
              CapturedHeroExecutedDetailsNotificationGenerator.Generator },
            { CapturedHeroExiledDetails, CapturedHeroExiledDetailsNotificationGenerator.Generator },
            { CapturedHeroImprisonedDetails,
              CapturedHeroImprisonedDetailsNotificationGenerator.Generator },
            { CapturedHeroReturnedDetails,
              CapturedHeroReturnedDetailsNotificationGenerator.Generator },
            { HeroDepartureDetails, HeroDepartureDetailsNotificationGenerator.Generator },
            { InvitationAcceptedDetails, InvitationAcceptedDetailsNotificationGenerator.Generator },
            { InvitationRejectedDetails, InvitationRejectedDetailsNotificationGenerator.Generator },
            { OutlawApprehendedDetails, OutlawApprehendedDetailsNotificationGenerator.Generator },
            { OutlawSpottedDetails, OutlawSpottedDetailsNotificationGenerator.Generator },
            { PrisonerExchangeDetails, PrisonerExchangeDetailsNotificationGenerator.Generator },
            { PrisonerExecutedDetails, PrisonerExecutedDetailsNotificationGenerator.Generator },
            { ProvinceHeldDetails, ProvinceHeldDetailsNotificationGenerator.Generator },
            { QuestFailed, QuestFailedDetailsNotificationGenerator.Generator },
            { QuestFulfilled, QuestFulfilledDetailsNotificationGenerator.Generator },
            { RansomPaidDetails, RansomPaidDetailsNotificationGenerator.Generator },
            { RansomRejectedDetails, RansomRejectedDetailsNotificationGenerator.Generator },
            { ShatteredArmyDetails, ShatteredArmyDetailsNotificationGenerator.Generator },
            { SuppressBeastsFailedDetails,
              SuppressBeastsFailedDetailsNotificationGenerator.Generator },
            { SuppressedBeastsDetails, SuppressBeastsSucceededNotificationGenerator.Generator },
            { SwearBrotherhoodDetails, SwearBrotherhoodDetailsNotificationGenerator.Generator },
            { TruceAcceptedDetails, TruceAcceptedDetailsNotificationGenerator.Generator },
            { TruceRejectedDetails, TruceRejectedDetailsNotificationGenerator.Generator },
            { AllianceAcceptedDetails, AllianceAcceptedDetailsNotificationGenerator.Generator },
            { AllianceRejectedDetails, AllianceRejectedDetailsNotificationGenerator.Generator },
            { BreakAllianceAcceptedDetails, BreakAllianceAcceptedNotificationGenerator.Generator },
            { VassalExiledDetails, VassalExiledDetailsNotificationGenerator.Generator },
            { WithdrewForTruce, WithdrewForTruceDetailsNotificationGenerator.Generator }
        };

        public static IEnumerable<Notification> GenerateNotifications(
                ActionResultView actionResultView,
                IGameModel currentModel) {
            IEnumerable<IEnumerable<Notification>> NestedEnumerable() {
                foreach (var arn in actionResultView.Notifications) {
                    if (arn.Details != null &&
                        ArnMap.TryGetValue(arn.Details.SealedValueCase, out var generator)) {
                        yield return generator(arn, currentModel);
                    } else if (
                            arn.Details is {} details &&
                            GenericNotificationGenerator.TypeNames.ContainsKey(
                                    details.SealedValueCase)) {
                        yield return GenericNotificationGenerator.Generator(arn, currentModel);
                    }
                }
            }

            return NestedEnumerable().SelectMany(x => x);
        }
    }
}