using System;
using Net.Eagle0.Eagle.Common;
using Net.Eagle0.Eagle.Views;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using static Net.Eagle0.Eagle.Common.QuestDetails;
using System.Linq;

namespace eagle {
    public class UnaffiliatedHeroRowController : TableRowController, System.IDisposable {
        public RawImage professionImage;
        public TMP_Text heroNameLabel;
        public TMP_Text questLabel;
        public TMP_Text strLabel;
        public TMP_Text agiLabel;
        public TMP_Text wisLabel;
        public TMP_Text chrLabel;
        public TMP_Text conLabel;

        public RawImage archeryImage;
        public RawImage fireImage;

        private DynamicHeroTextUpdater textUpdater = new DynamicHeroTextUpdater();
        private GeneratedTextListener questTextListener;

        public void SetUnaffiliatedHero(UnaffiliatedHeroBasics uh, IGameModel model) {
            professionImage.texture =
                    gameObject.GetComponentInParent<EagleCommonTextures>().Profession(
                            uh.Profession);
            if (professionImage.texture == null) {
                professionImage.color = Color.clear;
            } else {
                professionImage.color = Color.white;
            }

            // Use the NameTextId from UnaffiliatedHeroBasics
            textUpdater.SetHeroText(heroNameLabel, uh.NameTextId, "Hero");

            switch (uh.RecruitmentInfo.Status) {
                case RecruitmentStatus.HasQuest:
                    SetQuestText(uh.RecruitmentInfo.Quest, model);
                    break;
                default:
                    questLabel.text = DisplayNames.ShortRecruitmentStatusString(uh.RecruitmentInfo);
                    break;
            }

            if (model.Heroes.ContainsKey(uh.HeroId)) {
                var hero = model.Heroes[uh.HeroId];

                if (hero.Strength > 0) {
                    strLabel.text = hero.Strength.ToString();
                    agiLabel.text = hero.Agility.ToString();
                    wisLabel.text = hero.Wisdom.ToString();
                    chrLabel.text = hero.Charisma.ToString();
                    conLabel.text = hero.Constitution.ToString();

                    archeryImage.gameObject.SetActive(hero.ArcheryCapable);
                    fireImage.gameObject.SetActive(hero.StartFireCapable);
                } else {
                    strLabel.text = "";
                    agiLabel.text = "";
                    wisLabel.text = "";
                    chrLabel.text = "";
                    conLabel.text = "";
                }
            }
        }

        public void Dispose() {
            textUpdater?.Dispose();
            if (questTextListener != null) {
                ClientTextProvider.Provider.RemoveListener(questTextListener);
                questTextListener = null;
            }
        }

        private void OnDestroy() { Dispose(); }

        private void SetQuestText(Quest quest, IGameModel model) {
            if (quest == null) {
                questLabel.text = "There is nothing you can do";
                return;
            }

            switch (quest.Details.SealedValueCase) {
                case SealedValueOneofCase.DismissSpecificVassalQuest:
                    var targetHeroId = quest.Details.DismissSpecificVassalQuest.TargetHeroId;
                    SetDynamicHeroQuestText(
                            targetHeroId,
                            (heroName) => $"Dismiss {heroName}",
                            "Dismiss vassal",
                            model);
                    break;

                case SealedValueOneofCase.ExecutePrisonerQuest:
                    var executeDetails = quest.Details.ExecutePrisonerQuest;
                    var executeProvinceName = model.Provinces[executeDetails.ProvinceId].Name;
                    SetDynamicHeroQuestText(
                            executeDetails.PrisonerHeroId,
                            (heroName) => $"Execute {heroName} in {executeProvinceName}",
                            $"Execute prisoner in {executeProvinceName}",
                            model);
                    break;

                case SealedValueOneofCase.ExilePrisonerQuest:
                    var exileDetails = quest.Details.ExilePrisonerQuest;
                    var exileProvinceName = model.Provinces[exileDetails.ProvinceId].Name;
                    SetDynamicHeroQuestText(
                            exileDetails.PrisonerHeroId,
                            (heroName) => $"Exile {heroName} from {exileProvinceName}",
                            $"Exile prisoner from {exileProvinceName}",
                            model);
                    break;

                case SealedValueOneofCase.FreePrisonerQuest:
                    var freeDetails = quest.Details.FreePrisonerQuest;
                    var freeProvinceName = model.Provinces[freeDetails.ProvinceId].Name;
                    SetDynamicHeroQuestText(
                            freeDetails.PrisonerHeroId,
                            (heroName) => $"Release {heroName} from prison in {freeProvinceName}",
                            $"Release prisoner from prison in {freeProvinceName}",
                            model);
                    break;

                case SealedValueOneofCase.ReturnPrisonerQuest:
                    var returnDetails = quest.Details.ReturnPrisonerQuest;
                    var returnProvinceName = model.Provinces[returnDetails.ProvinceId].Name;
                    var returnFactionName = model.FactionName(returnDetails.ToFactionId);
                    SetDynamicHeroQuestText(
                            returnDetails.PrisonerHeroId,
                            (heroName) =>
                                    $"Return {heroName} from {returnProvinceName} to {returnFactionName}",
                            $"Return prisoner from {returnProvinceName} to {returnFactionName}",
                            model);
                    break;

                default:
                    // For all other quests, use the static method
                    questLabel.text = ShortQuestString(quest, model);
                    break;
            }
        }

        private void SetDynamicHeroQuestText(
                int heroId,
                System.Func<string, string> dynamicTextFunc,
                string fallbackText,
                IGameModel model) {
            if (!model.Heroes.ContainsKey(heroId)) {
                questLabel.text = fallbackText;
                return;
            }

            var hero = model.Heroes[heroId];

            // Check if the name is available immediately
            var textEntry = ClientTextProvider.Provider.GetTextEntry(hero.NameTextId);
            if (textEntry != null && !string.IsNullOrEmpty(textEntry.Text)) {
                questLabel.text = dynamicTextFunc(textEntry.Text);
            } else {
                // Set fallback text and create listener for dynamic updates
                questLabel.text = fallbackText;

                // Clean up any existing listener
                if (questTextListener != null) {
                    ClientTextProvider.Provider.RemoveListener(questTextListener);
                }

                // Create new listener for dynamic updates
                questTextListener =
                        new GeneratedTextListener(hero.NameTextId, "", "", 0, (index, heroName) => {
                            if (questLabel != null) { questLabel.text = dynamicTextFunc(heroName); }
                        });
                ClientTextProvider.Provider.AddListener(questTextListener);
            }
        }

        static string ShortQuestString(Quest quest, IGameModel model) {
            if (quest == null) { return $"There is nothing you can do"; }

            switch (quest.Details.SealedValueCase) {
                case SealedValueOneofCase.AllianceQuest:
                    return $"Secure an alliance with another faction";

                case SealedValueOneofCase.DefeatFactionQuest:
                    return $"Defeat {model.FactionName(quest.Details.DefeatFactionQuest.TargetFactionId)}";

                case SealedValueOneofCase.AlmsToProvinceQuest: {
                    var province = model.Provinces[quest.Details.AlmsToProvinceQuest.ProvinceId];
                    var desiredFood = quest.Details.AlmsToProvinceQuest.TotalFood;
                    var remainingFood = Math.Max(0, desiredFood - quest.ComponentsFulfilled);
                    var remainingText =
                            quest.ComponentsFulfilled > 0 ? $" ({remainingFood} remaining)" : "";
                    return $"Give {desiredFood} food in alms in {province.Name}{remainingText}";
                }

                case SealedValueOneofCase.AlmsAcrossRealmQuest: {
                    var desiredFood = quest.Details.AlmsAcrossRealmQuest.TotalFood;
                    var remainingFood = Math.Max(0, desiredFood - quest.ComponentsFulfilled);
                    var remainingText =
                            quest.ComponentsFulfilled > 0 ? $" ({remainingFood} remaining)" : "";
                    return $"Give {desiredFood} food in alms across the realm{remainingText}";
                }

                case SealedValueOneofCase.GiveToHeroesInProvinceQuest: {
                    var province =
                            model.Provinces[quest.Details.GiveToHeroesInProvinceQuest.ProvinceId];
                    var desiredGold = quest.Details.GiveToHeroesInProvinceQuest.TotalGold;
                    var remainingGold = Math.Max(0, desiredGold - quest.ComponentsFulfilled);
                    var remainingText =
                            quest.ComponentsFulfilled > 0 ? $" ({remainingGold} remaining)" : "";
                    return $"Give {desiredGold} gold to heroes in {province.Name}{remainingText}";
                }

                case SealedValueOneofCase.GiveToHeroesAcrossRealmQuest: {
                    var desiredGold = quest.Details.GiveToHeroesAcrossRealmQuest.TotalGold;
                    var remainingGold = Math.Max(0, desiredGold - quest.ComponentsFulfilled);
                    var remainingText =
                            quest.ComponentsFulfilled > 0 ? $" ({remainingGold} remaining)" : "";
                    return $"Give {desiredGold} gold to heroes across the realm{remainingText}";
                }

                case SealedValueOneofCase.ImproveAgricultureQuest:
                    return $"Raise Agriculture to {(int)Math.Ceiling(quest.Details.ImproveAgricultureQuest.DesiredValue)}";

                case SealedValueOneofCase.ImproveEconomyQuest:
                    return $"Raise Economy to {(int)Math.Ceiling(quest.Details.ImproveEconomyQuest.DesiredValue)}";

                case SealedValueOneofCase.ImproveInfrastructureQuest:
                    return $"Raise Infrastructure to {(int)Math.Ceiling(quest.Details.ImproveInfrastructureQuest.DesiredValue)}";

                case SealedValueOneofCase.SpecificExpansionQuest:
                    return $"Expand to {model.Provinces[quest.Details.SpecificExpansionQuest.ProvinceId].Name}";

                case SealedValueOneofCase.DismissSpecificVassalQuest:
                    // This case is handled by SetQuestText with dynamic updates, this is fallback
                    // only
                    return "Dismiss vassal";

                case SealedValueOneofCase.WealthQuest:
                    return $"Acquire {quest.Details.WealthQuest.Gold} gold and {quest.Details.WealthQuest.Food} food";

                case SealedValueOneofCase.UpgradeBattalionQuest:
                    return $"Raise a {DisplayNames.LongBattalionTypeNames[quest.Details.UpgradeBattalionQuest.BattalionTypeId]} to {(int)Math.Ceiling(quest.Details.UpgradeBattalionQuest.MinimumTraining)} training and {(int)Math.Ceiling(quest.Details.UpgradeBattalionQuest.MinimumArmament)} armament";

                case SealedValueOneofCase.GrandArmyQuest:
                    return $"Have {quest.Details.GrandArmyQuest.TotalTroopCount} troops";

                case SealedValueOneofCase.TruceWithFactionQuest:
                    return $"Sign a truce with {model.FactionName(quest.Details.TruceWithFactionQuest.TargetFactionId)}";

                case SealedValueOneofCase.TruceCountQuest: {
                    var currentTruceString = "";
                    if (model.PlayerId is int fid) {
                        var currentTruces = model.ActiveFactions[fid].FactionRelationships.Count(
                                fr => fr.RelationshipLevel !=
                                      FactionRelationshipView.Types.RelationshipLevel.Hostile);
                        if (currentTruces == 0) {
                            currentTruceString = " (currently have none)";
                        } else {
                            currentTruceString = " (currently have " + currentTruces + ")";
                        }
                    }
                    return $"Have truces with {quest.Details.TruceCountQuest.TruceCount} factions" +
                           currentTruceString;
                }

                default:
                    return $"Crosby hasn't gotten to quest of type {quest.Details.SealedValueCase} yet";
            }
        }
    }
}