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

namespace eagle.Notifications {
    using FactionId = Int32;
    using HeroId = Int32;

    public static class ProvinceEventsNotificationGenerator {
        public static readonly NotificationGenerator Generator = GenerateNotification;

        private static IEnumerable<Notification> GenerateNotification(
                ActionResultView actionResultView,
                IGameModel currentModel) {
            if (currentModel.PlayerId is FactionId playerId) {
                var cpsWithEvents = actionResultView.GameStateDiff.ChangedProvinces.Where(
                        p => p.EventsReplacement != null);
                var forPlayer = cpsWithEvents.Where(p => {
                    var province = currentModel.Provinces[p.Id];
                    return (province.RulingFactionId is FactionId rulingPlayer &&
                            rulingPlayer == playerId &&
                            province.FullInfo.RulingHeroId is HeroId rulingHeroId &&
                            currentModel.MaybeDestroyedFaction(playerId).Leaders.Contains(
                                    rulingHeroId)) ||
                           p.EventsReplacement.NewEvents.Count > 0;
                });

                foreach (var cp in forPlayer) {
                    var province = currentModel.Provinces[cp.Id];
                    var previousEventTypes =
                            province.KnownEvents.Select(e => e.SealedValueCase).ToList();
                    var newEventTypes =
                            cp.EventsReplacement.NewEvents.Select(e => e.SealedValueCase)
                                    .Distinct();

                    var displayedHeroes = new List<HeroView>();
                    if (province.RulingFactionId is FactionId rulingPlayer &&
                        rulingPlayer != playerId) {
                        var factionLeaderId =
                                currentModel.MaybeDestroyedFaction(rulingPlayer).FactionHeadId;
                        displayedHeroes.Add(currentModel.Heroes[factionLeaderId]);
                    }

                    foreach (var type in newEventTypes) {
                        if (!previousEventTypes.Contains(type)) {
                            switch (type) {
                                case ProvinceEvent.SealedValueOneofCase.BeastsEvent:
                                    var beastEvent = cp.EventsReplacement.NewEvents
                                                             .First(ae => ae.BeastsEvent != null)
                                                             .BeastsEvent;
                                    var beastInfo = beastEvent.BeastInfo;

                                    if (beastEvent.Count == 1) {
                                        var typeName = beastInfo.SingularName;
                                        var upper = DisplayNames.Capitalized(typeName);

                                        yield return new Notification(
                                                title: $"{upper} Appeared",
                                                text:
                                                $"A {typeName} is {DisplayNames.BeastEffectString(beastInfo)} in {province.Name}!",
                                                singleProvinceId: cp.Id,
                                                displayedHeroes: displayedHeroes);
                                    } else {
                                        var typeName = beastInfo.PluralName;
                                        var upper = DisplayNames.Capitalized(typeName);

                                        yield return new Notification(
                                                title: $"{upper} Appeared",
                                                text:
                                                $"{upper} are {DisplayNames.BeastEffectString(beastInfo)} in {province.Name}!",
                                                singleProvinceId: cp.Id,
                                                displayedHeroes: displayedHeroes);
                                    }
                                    break;

                                case ProvinceEvent.SealedValueOneofCase.BlizzardEvent:
                                    yield return new Notification(
                                            title: "A Winter Storm",
                                            text:
                                            $"A blizzard is has prevented any travel in {province.Name}!",
                                            singleProvinceId: cp.Id,
                                            displayedHeroes: displayedHeroes);
                                    break;

                                case ProvinceEvent.SealedValueOneofCase.ImminentRiotEvent: break;

                                case ProvinceEvent.SealedValueOneofCase.FestivalEvent:
                                    yield return new Notification(
                                            title: "A Festival!",
                                            text:
                                            $"A festival has begun in {province.Name}. Everyone is dancing!",
                                            singleProvinceId: cp.Id,
                                            displayedHeroes: displayedHeroes);
                                    break;

                                case ProvinceEvent.SealedValueOneofCase.FloodEvent:
                                    yield return new Notification(
                                            title: "Flood Waters Rising",
                                            text:
                                            $"A flood is causing destruction in {province.Name}.",
                                            singleProvinceId: cp.Id,
                                            displayedHeroes: displayedHeroes);
                                    break;

                                case ProvinceEvent.SealedValueOneofCase.DroughtEvent:
                                    yield return new Notification(
                                            title: "Drought",
                                            text: $"{province.Name} suffers from a serious drought.",
                                            singleProvinceId: cp.Id,
                                            displayedHeroes: displayedHeroes);
                                    break;

                                case ProvinceEvent.SealedValueOneofCase.EpidemicEvent:
                                    yield return new Notification(
                                            "Plague",
                                            $"A terrible epidemic has broken out in {province.Name}.",
                                            cp.Id,
                                            displayedHeroes: displayedHeroes);
                                    break;

                                case ProvinceEvent.SealedValueOneofCase.None: break;
                            }
                        }
                    }
                }
            }
        }
    }
}