using System;
using System.Collections.Generic;
using System.Linq;
using Net.Eagle0.Eagle.Api;
using Net.Eagle0.Eagle.Views;
using TMPro;
using UnityEngine.UI;

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

    public class HeroGiftCommandSelector : CommandSelector {
        private GeneratedTextListener warningTextListener;
        private string cachedWarningText = "";
        public TMP_Dropdown provinceDropdown;
        public HeroDropdownController heroDropdownController;
        public Slider goldSlider;
        public TMP_Text goldGivenLabel;

        private HeroGiftAvailableCommand HeroGiftCommand => _availableCommand.HeroGiftCommand;
        private ProvinceId ActingProvinceId => HeroGiftCommand.ActingProvinceId;

        private ProvinceId? FilterProvince =>
                provinceDropdown.value == 0 ? null
                                            : (ProvinceId?)HeroGiftCommand.EligibleGifts
                                                      .GroupBy(eg => eg.RecipientProvinceId)
                                                      .ToList()[provinceDropdown.value - 1]
                                                      .Key;

        private List<EligibleGift> FilteredEligibleGifts =>
                FilterProvince == null
                        ? HeroGiftCommand.EligibleGifts.ToList()
                        : HeroGiftCommand.EligibleGifts
                                  .Where(eg => eg.RecipientProvinceId == FilterProvince.Value)
                                  .ToList();

        private List<HeroId> AvailableHeroIds =>
                FilteredEligibleGifts.Select(eg => eg.RecipientHeroId).ToList();

        private HeroId SelectedHeroId => heroDropdownController.SelectedHeroId;
        private HeroView SelectedHero => _model.Heroes[SelectedHeroId];

        private int AvailableGold => HeroGiftCommand.EligibleGifts.ToList()
                                             .Find(eg => eg.RecipientHeroId == SelectedHeroId)
                                             .GoldAvailable;
        private int SelectedGoldAmount => (int)goldSlider.value;

        public override AvailableCommand.SealedValueOneofCase CommandType =>
                AvailableCommand.SealedValueOneofCase.HeroGiftCommand;
        public override string HeaderString => "Give to Hero";
        public override string CommitButtonString => "Commit Gift";

        public override List<HeroId> TargetedHeroIds => new List<HeroId> { SelectedHeroId };
        public override bool HeroIsTargetable(HeroId heroId) =>
                HeroGiftCommand.EligibleGifts.Where(eg => eg.RecipientHeroId == heroId).Count() > 0;
        public override void AddTargetedHero(HeroId heroId) {
            var eligibleGift =
                    HeroGiftCommand.EligibleGifts.Where(eg => eg.RecipientHeroId == heroId).First();
            if (TargetedProvince.HasValue && TargetedProvince != eligibleGift.RecipientProvinceId)
                TargetedProvince = null;
            else
                heroDropdownController.SelectedHeroId = heroId;
        }

        public override bool EnableCommitButton => SelectedGoldAmount > 0;
        public override string DisabledCommitButtonReason => "Must send some gold";
        protected override ProvinceId? TargetedProvince {
            get => FilterProvince;
            set {
                var newIndex = 0;
                if (value is ProvinceId pid) {
                    var index = HeroGiftCommand.EligibleGifts.GroupBy(eg => eg.RecipientProvinceId)
                                        .Select(x => x.Key)
                                        .ToList()
                                        .IndexOf(pid);
                    if (index != -1) newIndex = index + 1;
                }

                if (newIndex != provinceDropdown.value) {
                    provinceDropdown.value = newIndex;
                    SetUpHeroDropdown();
                }
            }
        }
        public override bool WarnOnCommitButton => SelectedHero.Loyalty.Stat >= 100;
        public override string CommitWarningText => cachedWarningText;

        void Awake() {
            heroDropdownController.ConditionAccessor = hero => hero.Loyalty;
            heroDropdownController.ConditionName = "LOY";
        }

        protected override void SetUpUI() {
            provinceDropdown.ClearOptions();
            var availableProvinces =
                    HeroGiftCommand.EligibleGifts.GroupBy(eg => eg.RecipientProvinceId)
                            .Select(x => x.Key)
                            .ToList();
            var optionsList = new List<string> { "All" };
            optionsList.AddRange(availableProvinces.Select(pid => _model.Provinces[pid].Name));
            provinceDropdown.AddOptions(optionsList);

            provinceDropdown.value = 0;
            provinceDropdown.interactable = availableProvinces.Count() > 1;
            SetUpHeroDropdown();
            goldGivenLabel.text = "0";
            goldSlider.value = 0;
            goldSlider.maxValue = AvailableGold;
        }

        private void ClearWarningTextListener() {
            if (warningTextListener != null) {
                ClientTextProvider.Provider.RemoveListener(warningTextListener);
                warningTextListener = null;
            }
        }

        private void SetupWarningTextListener() {
            ClearWarningTextListener();

            if (!string.IsNullOrEmpty(SelectedHero.NameTextId)) {
                warningTextListener = new GeneratedTextListener(
                        SelectedHero.NameTextId,
                        "",
                        " already has maximum loyalty!",
                        0,
                        (index, text) => { cachedWarningText = text; });

                ClientTextProvider.Provider.AddListener(warningTextListener);
            }
        }

        public void SetUpHeroDropdown() {
            var heroes = AvailableHeroIds.Select(hid => _model.Heroes[hid]).ToList();

            heroDropdownController.AvailableHeroes = heroes;

            HeroView minLoyaltyHero = null;
            foreach (HeroView hero in heroes) {
                if (minLoyaltyHero == null || hero.Loyalty.Stat < minLoyaltyHero.Loyalty.Stat) {
                    minLoyaltyHero = hero;
                }
            }
            heroDropdownController.SelectedHeroId = minLoyaltyHero.Id;

            // Set up warning text listener for the selected hero
            SetupWarningTextListener();
        }

        public void HeroSelected() {
            goldSlider.maxValue = AvailableGold;
            goldSlider.value = Math.Min(goldSlider.value, AvailableGold);

            // Update warning text listener when hero selection changes
            SetupWarningTextListener();
        }

        public void GoldPlusClicked() {
            goldSlider.value =
                    Math.Min(goldSlider.value + KeyModifiedAmount.Amount(), AvailableGold);
        }

        public void GoldMinusClicked() {
            goldSlider.value = Math.Max(goldSlider.value - KeyModifiedAmount.Amount(), 0);
        }

        public void GoldSliderMoved(float value) { goldGivenLabel.text = ((int)value).ToString(); }

        public override SelectedCommand Command {
            get {
                var cmd = new SelectedCommand {
                    HeroGiftCommand =
                            new HeroGiftSelectedCommand {
                                RecipientHeroId = SelectedHeroId,
                                Amount = SelectedGoldAmount
                            }
                };

                return cmd;
            }
        }

        void OnDestroy() { ClearWarningTextListener(); }
    }
}
