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

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

    public class ApprehendOutlawCommandSelector : CommandSelector {
        private List<GeneratedTextListener> outlawListeners = new();
        private HeroId SelectedHeroId => actingHeroDropdownController.SelectedHeroId;
        private BattalionId? SelectedBattalionId =>
                actingBattalionDropdown.value == 0
                        ? null
                        : AvailableBattalions[actingBattalionDropdown.value - 1].Id;
        private HeroId TargetedHeroId => AvailableTargetHeroIds[targetOutlawDropdown.value];

        private ApprehendOutlawAvailableCommand ApprehendOutlawCommand =>
                _availableCommand.ApprehendOutlawCommand;
        private ProvinceId ActingProvinceId => ApprehendOutlawCommand.ActingProvinceId;

        public HeroDropdownController actingHeroDropdownController;
        public TMP_Dropdown actingBattalionDropdown;
        public TMP_Dropdown targetOutlawDropdown;

        public EagleCommonTextures textures;

        public override AvailableCommand.SealedValueOneofCase CommandType =>
                AvailableCommand.SealedValueOneofCase.ApprehendOutlawCommand;
        public override string HeaderString => "Apprehend Outlaw";
        public override string CommitButtonString => "Commit Apprehend Outlaw";

        public override bool HeroIsTargetable(HeroId heroId) =>
                ApprehendOutlawCommand.AvailableHeroIds.Contains(heroId);
        public override void AddTargetedHero(HeroId heroId) =>
                actingHeroDropdownController.SelectedHeroId = heroId;

        private List<HeroId> AvailableTargetHeroIds { get; set; }
        private ProvinceView Province => _model.Provinces[ActingProvinceId];
        private List<BattalionView> AvailableBattalions =>
                ApprehendOutlawCommand.AvailableBattalionIds
                        .Select(id => Province.FullInfo.Battalions.First(b => b.Id == id))
                        .OrderBy(batt => batt.Type)
                        .ToList();

        private void ClearOutlawListeners() {
            foreach (var listener in outlawListeners) {
                ClientTextProvider.Provider.RemoveListener(listener);
            }
            outlawListeners.Clear();
        }

        private void SetOutlawText(int index, string text) {
            if (index >= targetOutlawDropdown.options.Count) return;
            targetOutlawDropdown.options[index].text = text;
            targetOutlawDropdown.RefreshShownValue();
        }

        private string GetFactionSuffix(ResidentOutlaw outlaw) {
            if (outlaw.LastFactionId is FactionId fid) { return $" ({_model.FactionName(fid)})"; }
            return "";
        }

        private TMP_Dropdown.OptionData BattalionOption(BattalionView bv) {
            var texture = textures.BattalionType(bv.Type);
            return new TMP_Dropdown.OptionData {
                image = Sprite.Create(
                        texture,
                        new Rect(0, 0, texture.width, texture.height),
                        new Vector2(0.5f, 0.5f)),
                text = bv.Size.ToString()
            };
        }

        protected override void SetUpUI() {
            actingHeroDropdownController.AvailableHeroes =
                    ApprehendOutlawCommand.AvailableHeroIds.Select(hid => _model.Heroes[hid])
                            .ToList();

            AvailableTargetHeroIds =
                    ApprehendOutlawCommand.Outlaws.Select(uh => uh.Hero.Id).ToList();

            actingBattalionDropdown.ClearOptions();
            actingBattalionDropdown.AddOptions(
                    new List<TMP_Dropdown.OptionData> { new() { text = "No Battalion" } });
            actingBattalionDropdown.AddOptions(
                    AvailableBattalions.Select(BattalionOption).ToList());
            actingBattalionDropdown.value = Math.Min(1, AvailableBattalions.Count);

            targetOutlawDropdown.ClearOptions();

            ClearOutlawListeners();

            // Create empty options first, text will be populated by listeners
            var emptyOptions = ApprehendOutlawCommand.Outlaws
                                       .Select(
                                               _ => new TMP_Dropdown.OptionData { text = "" })
                                       .ToList();
            targetOutlawDropdown.AddOptions(emptyOptions);

            // Set up listeners for each outlaw's name text
            for (int i = 0; i < ApprehendOutlawCommand.Outlaws.Count; i++) {
                var outlaw = ApprehendOutlawCommand.Outlaws[i];
                var suffix = GetFactionSuffix(outlaw);

                if (!string.IsNullOrEmpty(outlaw.Hero.NameTextId)) {
                    var listener = new GeneratedTextListener(
                            outlaw.Hero.NameTextId,
                            "",
                            suffix,
                            i,
                            SetOutlawText);

                    outlawListeners.Add(listener);
                    ClientTextProvider.Provider.AddListener(listener);
                }
            }

            targetOutlawDropdown.value = 0;
        }

        public override SelectedCommand Command => new() {
            ApprehendOutlawSelectedCommand =
                    new ApprehendOutlawSelectedCommand {
                        HeroIdToApprehend = TargetedHeroId,
                        BattalionId = SelectedBattalionId,
                        ActingHeroId = SelectedHeroId
                    }
        };

        void OnDestroy() { ClearOutlawListeners(); }
    }
}
