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

namespace eagle {
    using ProvinceId = Int32;

    public class ManagePrisonersCommandSelector : CommandSelector {
        // Unity accessors
        public Toggle ReleaseToggle;
        public Toggle MoveToggle;
        public Toggle ExileToggle;
        public Toggle ExecuteToggle;
        public Toggle ReturnToggle;

        public RawImage ReleaseIcon;
        public RawImage MoveIcon;
        public RawImage ExileIcon;
        public RawImage ExecuteIcon;
        public RawImage ReturnIcon;

        public TMP_Dropdown moveToDropdown;

        public HeroDetailsController heroDetails;

        public TMP_Text MessageText;

        public Button NextHeroButton;

        public HeroView SelectedHero => SelectedPrisonerToManage.Prisoner.Hero;

        public override AvailableCommand.SealedValueOneofCase CommandType =>
                AvailableCommand.SealedValueOneofCase.ManagePrisonerCommand;
        public override string HeaderString => "Manage Prisoners";
        public override string CommitButtonString =>
                $"Commit {DisplayNames.PrisonerManagementTypeName(SelectedOption)}";

        private int _selectedHeroIndex;
        private PrisonerToManage SelectedPrisonerToManage =>
                ManagePrisonersCommand.Prisoners[_selectedHeroIndex];

        private ManagePrisonersAvailableCommand ManagePrisonersCommand =>
                _availableCommand.ManagePrisonerCommand;
        private ProvinceId ActingProvinceId => ManagePrisonersCommand.ActingProvinceId;

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

        private PrisonerManagementOption SelectedOption {
            get {
                if (ExecuteToggle.isOn)
                    return SelectedPrisonerToManage.AvailableOptions.First(
                            opt => opt.SealedValueCase ==
                                   PrisonerManagementOption.SealedValueOneofCase.Execute);
                else if (MoveToggle.isOn)
                    return SelectedPrisonerToManage.AvailableOptions
                            .Where(opt => opt.SealedValueCase ==
                                          PrisonerManagementOption.SealedValueOneofCase.Move)
                            .ElementAt(moveToDropdown.value);
                else if (ReleaseToggle.isOn)
                    return SelectedPrisonerToManage.AvailableOptions.First(
                            opt => opt.SealedValueCase ==
                                   PrisonerManagementOption.SealedValueOneofCase.Release);
                else if (ExileToggle.isOn)
                    return SelectedPrisonerToManage.AvailableOptions.First(
                            opt => opt.SealedValueCase ==
                                   PrisonerManagementOption.SealedValueOneofCase.Exile);
                else if (ReturnToggle.isOn)
                    return SelectedPrisonerToManage.AvailableOptions.First(
                            opt => opt.SealedValueCase ==
                                   PrisonerManagementOption.SealedValueOneofCase.Return);
                else
                    throw new ArgumentOutOfRangeException("Unknown prisoner management option");
            }
        }

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

        public override SelectedCommand Command => new SelectedCommand {
            ManagePrisonersCommand =
                    new ManagePrisonersSelectedCommand {
                        PrisonerHeroId = SelectedHero.Id,
                        ChosenOption = SelectedOption
                    }
        };

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

            DisplaySelectedHero();
        }

        public void MoveToggled(bool value) { moveToDropdown.gameObject.SetActive(value); }

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

            moveToDropdown.options =
                    SelectedPrisonerToManage.AvailableOptions
                            .Where(opt => opt.SealedValueCase ==
                                          PrisonerManagementOption.SealedValueOneofCase.Move)
                            .Select(opt => _model.Provinces[opt.Move.ToProvinceId].Name)
                            .Select(name => new TMP_Dropdown.OptionData(name))
                            .ToList();

            MessageText.text = "";

            // The order here is important: the last available toggle in this list
            // will be on by default
            ConditionallyEnable(
                    ExecuteToggle,
                    ExecuteIcon,
                    PrisonerManagementOption.SealedValueOneofCase.Execute);
            ConditionallyEnable(
                    ExileToggle,
                    ExileIcon,
                    PrisonerManagementOption.SealedValueOneofCase.Exile);
            ConditionallyEnable(
                    ReturnToggle,
                    ReturnIcon,
                    PrisonerManagementOption.SealedValueOneofCase.Return);
            ConditionallyEnable(
                    MoveToggle,
                    MoveIcon,
                    PrisonerManagementOption.SealedValueOneofCase.Move);
            ConditionallyEnable(
                    ReleaseToggle,
                    ReleaseIcon,
                    PrisonerManagementOption.SealedValueOneofCase.Release);
        }

        private bool ConditionallyEnable(
                Toggle toggle,
                PrisonerManagementOption.SealedValueOneofCase option) {
            bool enable = SelectedPrisonerToManage.AvailableOptions.Any(
                    opt => opt.SealedValueCase == option);
            toggle.gameObject.SetActive(enable);

            if (enable) {
                ExecuteToggle.isOn = false;
                ExileToggle.isOn = false;
                MoveToggle.isOn = false;
                ReleaseToggle.isOn = false;
                ReturnToggle.isOn = false;

                toggle.isOn = true;
            } else
                toggle.isOn = false;

            return enable;
        }

        private void ConditionallyEnable(
                Toggle toggle,
                RawImage img,
                PrisonerManagementOption.SealedValueOneofCase option) {
            bool enable = ConditionallyEnable(toggle, option);

            Color color = img.color;
            color.a = enable ? 1.0f : 0.25f;
            img.color = color;
        }
    }
}