using System;
using System.Collections.Generic;
using System.Linq;
using common;
using EagleGUIUtils;
using Net.Eagle0.Eagle.Common;
using Net.Eagle0.Eagle.Views;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

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

    public class ProvinceInfoPanelController : MonoBehaviour {
        private IGameModel _model;
        public IGameModel Model { private
            get => _model;
            set {
                _model = value;
                panel.SetActive(_model != null && _provinceView != null);
            }
        }

        public RawImage HeadshotImage;

        private bool _wideScreen;
        public bool WideScreen {
            set {
                if (value) {
                    provinceEventsContainer.gameObject.GetComponent<LayoutElement>()
                            .preferredWidth = 192;
                    provinceEventsContainer.gameObject.GetComponent<LayoutElement>().minWidth = 192;
                    provinceEventsContainer.gameObject.GetComponent<GridLayoutGroup>().cellSize =
                            new Vector2(56, 56);
                } else {
                    provinceEventsContainer.gameObject.GetComponent<LayoutElement>()
                            .preferredWidth = -1;
                    provinceEventsContainer.gameObject.GetComponent<LayoutElement>().minWidth = -1;
                    provinceEventsContainer.gameObject.GetComponent<GridLayoutGroup>().cellSize =
                            new Vector2(20, 20);
                }

                dominionViewToggle.gameObject.SetActive(!value);
                _wideScreen = value;
            }

            get => _wideScreen;
        }

        public GameObject panel;
        public TextMeshProUGUI ProvinceNameField;
        public RawImage entrustImage;
        public RawImage developImage;
        public RawImage expandImage;
        public RawImage mobilizeImage;
        public GeneratedTextUpdater provinceLeaderField;
        public TextMeshProUGUI provinceFactionField;
        public GameObject supportAndIndexContainer;
        public TextMeshProUGUI SupportField;

        public GameObject ProvinceDetailsContainer;
        public TextMeshProUGUI DiplomacyInfoField;
        public TextMeshProUGUI AsOfField;
        public TextMeshProUGUI UnderAttackField;

        public TextMeshProUGUI GoldField;
        public TextMeshProUGUI FoodField;
        public TextMeshProUGUI ConsumedField;
        public TextMeshProUGUI priceIndexField;

        public TextMeshProUGUI EconomyField;
        public TextMeshProUGUI AgricultureField;
        public TextMeshProUGUI InfrastructureField;

        public TextMeshProUGUI DevastationField;
        public TextMeshProUGUI CommandersField;
        public TextMeshProUGUI FreeHeroesField;

        public TextMeshProUGUI BattalionsField;
        public TextMeshProUGUI TroopsField;
        public TextMeshProUGUI CastleCountField;

        public GameObject provinceEventsContainer;
        public RawImage droughtImage;
        public RawImage beastsImage;
        public RawImage blizzardImage;
        public RawImage floodImage;
        public RawImage epidemicImage;
        public RawImage festivalImage;

        public DominionPanelController dominionPanelController;
        public DisclosureTriangle dominionViewToggle;

        private ProvinceView _provinceView;
        private DynamicFactionTextUpdater factionTextUpdater = new DynamicFactionTextUpdater();

        private void SetHeadshotToHeroId(HeroId hid) {
            var rulingHero = _model.Heroes[hid];

            if (rulingHero.ImagePath is String path) {
                HeadshotImage.gameObject.SetActive(true);
                ResourceFetcher.headshotFetcher.LoadIntoRawImage(HeadshotImage, path);
            } else {
                HeadshotImage.gameObject.SetActive(false);
            }
        }

        private void PopulateHeadshot() {
            Color c = HeadshotImage.color;
            c.a = 1.0f;
            if (_provinceView?.FullInfo?.RulingHeroId is HeroId rulingHid) {
                SetHeadshotToHeroId(rulingHid);
            } else if (_provinceView?.RulingFactionId is FactionId fid) {
                SetHeadshotToHeroId(_model.ActiveFactions[fid].FactionHeadId);

                c.a = 0.5f;
            } else {
                HeadshotImage.gameObject.SetActive(false);
            }
            HeadshotImage.color = c;
        }

        private void PopulateProvinceEvents() {
            provinceEventsContainer.gameObject.SetActive(false);

            blizzardImage.gameObject.SetActive(false);
            floodImage.gameObject.SetActive(false);
            epidemicImage.gameObject.SetActive(false);
            festivalImage.gameObject.SetActive(false);
            droughtImage.gameObject.SetActive(false);
            beastsImage.gameObject.SetActive(false);
            foreach (var ae in Province.KnownEvents) {
                switch (ae.SealedValueCase) {
                    case ProvinceEvent.SealedValueOneofCase.BeastsEvent: {
                        var beastsEvent = ae.BeastsEvent;
                        string tooltipText = "";
                        if (beastsEvent.Count > 1) {
                            tooltipText = $"{beastsEvent.Count} {beastsEvent.BeastInfo.PluralName}";
                        } else {
                            tooltipText = $"A {beastsEvent.BeastInfo.SingularName}";
                        }
                        provinceEventsContainer.gameObject.SetActive(true);
                        beastsImage.gameObject.SetActive(true);
                        beastsImage
                                .GetComponentInParent<HoveringTooltipTextProvider>(
                                        includeInactive: true)
                                .text = tooltipText;
                        break;
                    }
                    case ProvinceEvent.SealedValueOneofCase.ImminentRiotEvent:
                        // No image since this gets a modal event
                        break;

                    case ProvinceEvent.SealedValueOneofCase.BlizzardEvent:
                        provinceEventsContainer.gameObject.SetActive(true);
                        blizzardImage.gameObject.SetActive(true);
                        break;

                    case ProvinceEvent.SealedValueOneofCase.FestivalEvent:
                        provinceEventsContainer.gameObject.SetActive(true);
                        festivalImage.gameObject.SetActive(true);
                        break;

                    case ProvinceEvent.SealedValueOneofCase.FloodEvent:
                        provinceEventsContainer.gameObject.SetActive(true);
                        floodImage.gameObject.SetActive(true);
                        break;

                    case ProvinceEvent.SealedValueOneofCase.DroughtEvent:
                        provinceEventsContainer.gameObject.SetActive(true);
                        droughtImage.gameObject.SetActive(true);
                        break;

                    case ProvinceEvent.SealedValueOneofCase.EpidemicEvent:
                        provinceEventsContainer.gameObject.SetActive(true);
                        epidemicImage.gameObject.SetActive(true);
                        break;
                }
            }
        }

        private void PopulateFullInfo(FullProvinceInfo fullInfo) {
            if (fullInfo == null) {
                throw new ArgumentNullException("cannot populate details without fullInfo");
            }

            SupportField.text =
                    $"{GUIUtils.ConditionString(Province.FullInfo.Support, lightColors: true)}";

            bool ownProvince = _provinceView.RulingFactionId == Model.PlayerId;
            var underAttack =
                    ownProvince && Province.KnownIncomingArmies.Any(
                                           x => x.FactionId != Model.PlayerId && x.HeroCount > 0);
            AsOfField.gameObject.SetActive(false);

            if (ownProvince) {
                panel.GetComponent<Image>().color =
                        underAttack ? GUIUtils.UnderAttackPanelColor : GUIUtils.PanelColor;
                UnderAttackField.gameObject.SetActive(underAttack);
            }

            if (fullInfo.ProvinceOrders != ProvinceOrderType.UnknownOrders) {
                AsOfField.gameObject.SetActive(false);
                switch (Province.FullInfo.ProvinceOrders) {
                    case ProvinceOrderType.Entrust: entrustImage.gameObject.SetActive(true); break;
                    case ProvinceOrderType.Develop: developImage.gameObject.SetActive(true); break;
                    case ProvinceOrderType.Expand: expandImage.gameObject.SetActive(true); break;
                    case ProvinceOrderType.Mobilize:
                        mobilizeImage.gameObject.SetActive(true);
                        break;
                }
            } else if (Province.AsOf != null) {
                AsOfField.text = $"As of {DisplayNames.DateString(Province.AsOf)}";
                AsOfField.gameObject.SetActive(true);
            }

            bool overFoodCap = Province.FullInfo.Food > Province.FullInfo.FoodCap;
            bool overGoldCap = Province.FullInfo.Gold > Province.FullInfo.GoldCap;
            GoldField.text =
                    $"{GUIUtils.PossiblyColoredString(overGoldCap, Color.red, Province.FullInfo.Gold.ToString())} / {Province.FullInfo.GoldCap}";
            FoodField.text =
                    $"{GUIUtils.PossiblyColoredString(overFoodCap, Color.red, Province.FullInfo.Food.ToString())} / {Province.FullInfo.FoodCap}";
            ConsumedField.text = $"{Province.FullInfo.FoodConsumption}";
            priceIndexField.text = $"{Province.FullInfo.PriceIndex,4:F2}";

            EconomyField.text = $"{ProvinceStatUtils.RoundedStat(Province.FullInfo.Economy)}";
            if (Province.FullInfo.EconomyDevastation > 0) {
                var devastatedEconomy =
                        $"{ProvinceStatUtils.RoundedStat(Math.Max(0.0f, Province.FullInfo.Economy - Province.FullInfo.EconomyDevastation))}";
                EconomyField.text += $" ({GUIUtils.ColoredString(Color.red, devastatedEconomy)})";
            }

            AgricultureField.text =
                    $"{ProvinceStatUtils.RoundedStat(Province.FullInfo.Agriculture)}";
            if (Province.FullInfo.AgricultureDevastation > 0) {
                var devastatedAgriculture =
                        $"{ProvinceStatUtils.RoundedStat(Math.Max(0.0f, Province.FullInfo.Agriculture - Province.FullInfo.AgricultureDevastation))}";
                AgricultureField.text +=
                        $" ({GUIUtils.ColoredString(Color.red, devastatedAgriculture)})";
            }

            InfrastructureField.text =
                    $"{ProvinceStatUtils.RoundedStat(Province.FullInfo.Infrastructure)}";
            if (Province.FullInfo.InfrastructureDevastation > 0) {
                var devastatedInfrastructure =
                        $"{ProvinceStatUtils.RoundedStat(Math.Max(0.0f, Province.FullInfo.Infrastructure - Province.FullInfo.InfrastructureDevastation))}";
                InfrastructureField.text +=
                        $" ({GUIUtils.ColoredString(Color.red, devastatedInfrastructure)})";
            }

            var totalDevastation = Province.FullInfo.EconomyDevastation +
                                   Province.FullInfo.AgricultureDevastation +
                                   Province.FullInfo.InfrastructureDevastation;
            var totalDevastationString =
                    $"{ProvinceStatUtils.RoundedDevastation(totalDevastation)}";
            if (totalDevastation > 0) {
                DevastationField.text =
                        $"{GUIUtils.ColoredString(Color.red, totalDevastationString)}";
            } else {
                DevastationField.text = totalDevastationString;
            }

            var heroCount = Province.FullInfo.RulingFactionHeroIds.Count;
            var heroCountString = $"{heroCount}";
            if (Province.FullInfo.HeroCap >= Province.FullInfo.RulingFactionHeroIds.Count) {
                CommandersField.text = heroCountString;
            } else {
                CommandersField.text = $"{GUIUtils.ColoredString(Color.red, heroCountString)}";
            }
            FreeHeroesField.text = $"{Province.FullInfo?.UnaffiliatedHeroes.Count ?? 0}";

            BattalionsField.text = $"{Province.FullInfo.Battalions.Count}";
            TroopsField.text = $"{Province.FullInfo.Battalions.Select(batt => batt.Size).Sum()}";
            CastleCountField.text = $"{Province.FullInfo.CastleCount}";
        }

        public ProvinceView Province {
            get => _provinceView;
            set {
                DiplomacyInfoField.gameObject.SetActive(false);
                ProvinceDetailsContainer.SetActive(false);
                supportAndIndexContainer.SetActive(false);

                entrustImage.gameObject.SetActive(false);
                developImage.gameObject.SetActive(false);
                expandImage.gameObject.SetActive(false);
                mobilizeImage.gameObject.SetActive(false);

                _provinceView = value;
                if (_provinceView != null) {
                    panel.SetActive(true);

                    var hasFullInfo = Province.FullInfo != null;

                    PopulateHeadshot();
                    PopulateProvinceEvents();

                    if (hasFullInfo) {
                        PopulateFullInfo(Province.FullInfo);

                        supportAndIndexContainer.SetActive(true);
                        ProvinceDetailsContainer.SetActive(true);
                    }

                    if (Province.RulingFactionId.HasValue) {
                        var faction = Model.MaybeDestroyedFaction(Province.RulingFactionId.Value);

                        string rulingHeroNameTextId = "";
                        string rulingHeroPrefix = "";
                        if (hasFullInfo && Province.FullInfo.RulingHeroId is HeroId hid &&
                            Model.Heroes[hid] is HeroView hero) {
                            rulingHeroNameTextId = hero.NameTextId;
                            rulingHeroPrefix = "";
                        } else {
                            rulingHeroNameTextId = "";
                            rulingHeroPrefix = "UNKNOWN";
                        }

                        ProvinceNameField.text = Province.Name;
                        provinceLeaderField.TextId = rulingHeroNameTextId;
                        provinceLeaderField.PrefixedText = rulingHeroPrefix;
                        factionTextUpdater.SetFactionText(provinceFactionField, faction, Model);

                        var diploStrings = new List<string>();
                        if (!hasFullInfo) {
                            if (Model.PlayerId.HasValue) {
                                DiplomacyInfoField.text = "";
                                foreach (var fr in faction.FactionRelationships) {
                                    if (fr.TargetFactionId == Model.PlayerId) {
                                        switch (fr.RelationshipLevel) {
                                            case FactionRelationshipView.Types.RelationshipLevel
                                                    .Truce:
                                                diploStrings.Add(
                                                        $"We have a treaty with them until {DisplayNames.DateString(fr.ResetDate)}.");
                                                break;

                                            default: break;
                                        }
                                    }
                                }
                                foreach (var offer in Model.MaybeDestroyedFaction(faction.Id)
                                                 .IncomingDiplomacyOffers) {
                                    if (offer.OriginatingFactionId == Model.PlayerId) {
                                        switch (offer.OfferDetails.SealedValueCase) {
                                            case DiplomacyOfferDetails.SealedValueOneofCase
                                                    .TruceOffer:
                                                diploStrings.Add(
                                                        "We have a treaty offer en route to them.");
                                                break;
                                            case DiplomacyOfferDetails.SealedValueOneofCase
                                                    .Invitation:
                                                diploStrings.Add(
                                                        "We have an invitation en route to them.");
                                                break;
                                            case DiplomacyOfferDetails.SealedValueOneofCase
                                                    .RansomOffer:
                                                diploStrings.Add(
                                                        "We have a ransom offer en route to them.");
                                                break;
                                        }
                                    }
                                }
                                DiplomacyInfoField.gameObject.SetActive(true);
                            }
                        }
                        DiplomacyInfoField.text = String.Join('\n', diploStrings);

                    } else {
                        ProvinceNameField.text = Province.Name;
                        provinceLeaderField.TextId = "";
                        provinceLeaderField.PrefixedText = "";
                        provinceFactionField.text = "Free Province";
                    }
                } else {
                    panel.SetActive(false);
                    ProvinceDetailsContainer.SetActive(false);
                }
            }
        }

        public void DominionViewToggleClicked(bool value) {
            dominionPanelController.gameObject.SetActive(value);
            this.gameObject.SetActive(!value);
        }

        void Start() { panel.SetActive(false); }

        private void OnEnable() {
            if (dominionViewToggle != null) { dominionViewToggle.isOn = false; }
        }

        void Update() {
            if (Model == null) {
                panel.SetActive(false);
            } else {
                panel.SetActive(true);
            }

            if (!WideScreen && Input.GetButtonUp("Toggle Dominion Table")) {
                dominionViewToggle.isOn = !dominionViewToggle.isOn;
            }
        }

        private void OnDestroy() { factionTextUpdater?.Dispose(); }
    }
}