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

namespace eagle {
    using HeroId = Int32;

    public class HeroDropdownController : MonoBehaviour {
        private TMP_Dropdown Dropdown => gameObject.GetComponent<TMP_Dropdown>();
        public RawImage HeadshotImage;
        public bool showCondition = true;

        public delegate StatWithCondition accessor(HeroView hero);
        public accessor ConditionAccessor = hero => hero.Vigor;
        public string ConditionName = "VIG";

        private List<HeroView> _availableHeroes;
        public List<HeroView> AvailableHeroes {
            get => _availableHeroes;
            set {
                _availableHeroes = new List<HeroView>(value);
                options = _availableHeroes.Select(HeroOption).ToList();
                AssignOptions();

                ClearListeners();
                listeners = new List<SingleEntryListener>();
                for (int i = 0; i < _availableHeroes.Count; i++) {
                    HeroView hero = _availableHeroes[i];
                    var listener = new SingleEntryListener(
                            hero.NameTextId,
                            "",
                            showCondition
                                    ? $" ({GUIUtils.ConditionString(ConditionAccessor(hero), ConditionName)})"
                                    : "",
                            i,
                            SetGeneratedText);

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

                SetHeadshot();
            }
        }

        public string FallbackText = "";

        private void SetGeneratedText(int index, string text) {
            if (index >= Dropdown.options.Count) return;
            options[index].text = text;
            AssignOptions();
        }

        private List<TMP_Dropdown.OptionData> options = new();
        public void AssignOptions() {
            Dropdown.ClearOptions();
            Dropdown.AddOptions(options);
            Dropdown.RefreshShownValue();
        }

        private List<SingleEntryListener> listeners = new();

        private void ClearListeners() {
            foreach (var listener in listeners) {
                ClientTextProvider.Provider.RemoveListener(listener);
            }

            listeners.Clear();
        }

        private class SingleEntryListener : IClientTextListener {
            private readonly string textId;
            private readonly string prefix;
            private readonly string suffix;
            private readonly int index;
            private readonly Action<int, string> onTextUpdate;

            public void OnTextUpdate(string text, bool completed) {
                onTextUpdate(index, $"{prefix}{text}{suffix}");
            }

            public string TextId() { return textId; }

            public SingleEntryListener(
                    string textId,
                    string prefix,
                    string suffix,
                    int idx,
                    Action<int, string> callback) {
                this.textId = textId;
                this.prefix = prefix;
                this.suffix = suffix;
                this.index = idx;
                this.onTextUpdate = callback;
            }
        }

        public int SelectedIndex => Dropdown.value;

        public HeroId SelectedHeroId {
            get => AvailableHeroes[Dropdown.value].Id;
            set {
                Dropdown.value = AvailableHeroes.FindIndex(h => h.Id == value);
                DropdownUpdated(Dropdown.value);
            }
        }

        public Action SelectedHeroIdUpdated;

        void Start() { Dropdown.onValueChanged.AddListener(DropdownUpdated); }

        private void SetHeadshot() {
            var imagePath = AvailableHeroes[Dropdown.value].ImagePath;
            if (!string.IsNullOrEmpty(imagePath)) {
                ResourceFetcher.headshotFetcher.LoadIntoRawImage(HeadshotImage, imagePath);
            }
        }

        void DropdownUpdated(int newValue) {
            var egc = gameObject.GetComponentInParent<EagleGameController>();
            if (egc != null) {
                egc.GetComponentInChildren<HeroesAndBattalionsPanelController>()
                        .UpdateHeroSelections();
            }

            SetHeadshot();

            if (SelectedHeroIdUpdated != null) SelectedHeroIdUpdated.Invoke();
        }

        private TMP_Dropdown.OptionData HeroOption(HeroView hv) {
            var texture = !Textures ? null : Textures.Profession(hv.Profession);

            var op = new TMP_Dropdown.OptionData {
                image = !texture ? null
                                 : Sprite.Create(
                                           texture,
                                           new Rect(0, 0, texture.width, texture.height),
                                           new Vector2(0.5f, 0.5f)),
                text = String.IsNullOrEmpty(hv.NameTextId) ? FallbackText : ""
            };

            return op;
        }

        private EagleCommonTextures Textures =>
                gameObject.GetComponentInParent<EagleCommonTextures>();
    }
}
