using System;
using Net.Eagle0.Eagle.Api;
using Net.Eagle0.Eagle.Api.Command.Util;
using Net.Eagle0.Eagle.Views;
using UnityEngine;
using UnityEngine.UI;

namespace eagle {
    using ProvinceId = Int32;

    public class HandleCapturedHeroesCommandSelector : CommandSelector {
        // Unity accessors
        public Toggle RecruitToggle;
        public Toggle ImprisonToggle;
        public Toggle ExileToggle;
        public Toggle ExecuteToggle;
        public Toggle ReturnToggle;
        public ToggleGroup decisionToggleGroup;

        public HeroDetailsController heroDetails;

        public GeneratedTextUpdater messageUpdater;

        public Button NextHeroButton;

        public HeroView SelectedHero => SelectedHeroWithOptions.Hero;

        public override AvailableCommand.SealedValueOneofCase CommandType =>
                AvailableCommand.SealedValueOneofCase.HandleCapturedHeroCommand;
        public override string HeaderString => "Handle Captured Hero";
        public override string CommitButtonString =>
                $"Commit {DisplayNames.CapturedHeroOptionNames[SelectedOption]}";

        private int _selectedHeroIndex;
        private ExpandedCapturedHero SelectedHeroWithOptions =>
                HandleCapturedHeroCommand.AvailableHeroes[_selectedHeroIndex];

        private HandleCapturedHeroAvailableCommand HandleCapturedHeroCommand =>
                _availableCommand.HandleCapturedHeroCommand;
        private ProvinceId ActingProvinceId => HandleCapturedHeroCommand.ActingProvinceId;

        public override bool WarnOnCommitButton =>
                SelectedOption == CapturedHeroOption.ReturnCapturedHeroOption;
        public override string CommitWarningText =>
                $"This will create a treaty with {_model.FactionName(SelectedHero.FactionId.Value)}";

        private CapturedHeroOption SelectedOption {
            get {
                if (RecruitToggle.isOn) return CapturedHeroOption.RecruitCapturedHeroOption;
                else if (ImprisonToggle.isOn)
                    return CapturedHeroOption.ImprisonCapturedHeroOption;
                else if (ExileToggle.isOn)
                    return CapturedHeroOption.ExileCapturedHeroOption;
                else if (ExecuteToggle.isOn)
                    return CapturedHeroOption.ExecuteCapturedHeroOption;
                else if (ReturnToggle.isOn)
                    return CapturedHeroOption.ReturnCapturedHeroOption;
                else
                    throw new ArgumentOutOfRangeException("Unknown captured hero option");
            }
        }

        protected override void SetUpUI() {
            if (_selectedHeroIndex >= HandleCapturedHeroCommand.AvailableHeroes.Count)
                _selectedHeroIndex = 0;
            NextHeroButton.gameObject.SetActive(
                    HandleCapturedHeroCommand.AvailableHeroes.Count > 1);
            DisplaySelectedHero();
        }

        public override SelectedCommand Command => new SelectedCommand {
            HandleCapturedHeroCommand =
                    new HandleCapturedHeroSelectedCommand() {
                        HeroId = SelectedHero.Id,
                        SelectedOption = SelectedOption
                    }
        };

        public void NextHeroButtonClicked() {
            _selectedHeroIndex++;
            if (_selectedHeroIndex >= HandleCapturedHeroCommand.AvailableHeroes.Count) {
                _selectedHeroIndex = 0;
            }

            DisplaySelectedHero();
        }

        private void DisplaySelectedHero() {
            heroDetails.SetHero(SelectedHero, _model);

            messageUpdater.TextId = SelectedHeroWithOptions.MessageId;

            var options = SelectedHeroWithOptions.Options;
            ConfigureToggle(
                    RecruitToggle,
                    options.Contains(CapturedHeroOption.RecruitCapturedHeroOption));
            ConfigureToggle(
                    ImprisonToggle,
                    options.Contains(CapturedHeroOption.ImprisonCapturedHeroOption));
            ConfigureToggle(
                    ExileToggle,
                    options.Contains(CapturedHeroOption.ExileCapturedHeroOption));
            ConfigureToggle(
                    ExecuteToggle,
                    options.Contains(CapturedHeroOption.ExecuteCapturedHeroOption));
            ConfigureToggle(
                    ReturnToggle,
                    options.Contains(CapturedHeroOption.ReturnCapturedHeroOption));

            // Select first available option (priority order: Recruit > Imprison > Exile > Execute >
            // Return)
            if (options.Contains(CapturedHeroOption.RecruitCapturedHeroOption))
                RecruitToggle.isOn = true;
            else if (options.Contains(CapturedHeroOption.ImprisonCapturedHeroOption))
                ImprisonToggle.isOn = true;
            else if (options.Contains(CapturedHeroOption.ExileCapturedHeroOption))
                ExileToggle.isOn = true;
            else if (options.Contains(CapturedHeroOption.ExecuteCapturedHeroOption))
                ExecuteToggle.isOn = true;
            else if (options.Contains(CapturedHeroOption.ReturnCapturedHeroOption))
                ReturnToggle.isOn = true;
        }

        private const float DisabledAlpha = 0.35f;

        private void ConfigureToggle(Toggle toggle, bool available) {
            if (toggle == null) return;

            toggle.gameObject.SetActive(true);
            toggle.interactable = available;

            // Remove from group BEFORE setting isOn to false. Otherwise,
            // ToggleGroup (with allowSwitchOff=false) can force the toggle
            // back to ON when it's the last active member, leaving a stale
            // isOn=true after the toggle is removed from the group.
            toggle.group = null;
            if (!available) { toggle.isOn = false; }

            toggle.group = available ? decisionToggleGroup : null;

            var canvasGroup = toggle.GetComponent<CanvasGroup>();
            if (canvasGroup == null) {
                canvasGroup = toggle.gameObject.AddComponent<CanvasGroup>();
            }
            canvasGroup.alpha = available ? 1f : DisabledAlpha;
        }
    }
}
