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

namespace eagle {
    public class HeroesAndBattalionsPanelController : MonoBehaviour {
        public GameObject panel;
        public GameObject popupPanel;
        public HeroDetailsController popupPanelDetailsController;
        public GeneratedTextUpdater popupPanelBackstory;

        private ProvinceView _currentProvince;
        public ProvinceView CurrentProvince {
            get => _currentProvince;
            set {
                if (_currentProvince != value) {
                    _currentProvince = value;
                    UpdateTables();
                }
            }
        }

        private IGameModel _model;
        public IGameModel Model { private
            get => _model;
            set {
                _model = value;
                UpdateTables();
                panel.SetActive(value != null);
            }
        }

        public GameObject heroesAndBattalionsViews;
        public EventBasedTable heroesTable;
        public EventBasedTable battalionsTable;

        public CommandPanelController commandPanelController;

        private CommandSelector CommandSelector =>
                commandPanelController == null ? null : commandPanelController.Selector;

        public void UpdateTables() {
            if (Model == null) {
                panel.SetActive(false);
                return;
            }
            panel.SetActive(true);
            SetUpHeroesTable();
            SetUpBattalionsTable();
        }

        private void SetHeroRowSelections(HeroRowController row, HeroView hero) {
            if (CommandSelector == null) {
                row.Selected = false;
                row.Selectable = false;
                row.RightSelectable = false;
            } else {
                row.Selected = CommandSelector.TargetedHeroIds.Contains(hero.Id);
                row.Selectable = CommandSelector.HeroIsTargetable(hero.Id);
                row.RightSelectable = CommandSelector.TargetedHeroIds.Contains(hero.Id);
            }
        }

        private void SetBattalionRowSelections(BattalionRowController row, BattalionView batt) {
            if (CommandSelector == null) {
                row.Selected = false;
                row.Selectable = false;
                row.RightSelectable = false;
            } else {
                row.Selected = CommandSelector.TargetedBattalionIds.Contains(batt.Id);
                row.Selectable = CommandSelector.BattalionIsTargetable(batt.Id);
                row.RightSelectable = CommandSelector.TargetedBattalionIds.Contains(batt.Id);
            }
        }

        public void UpdateHeroSelections() {
            Heroes.Each(
                    (hero, i) => SetHeroRowSelections(
                            heroesTable.ComponentAt<HeroRowController>(i),
                            hero));
        }

        public void UpdateBattalionSelections() {
            Battalions.Each(
                    (batt, i) => SetBattalionRowSelections(
                            battalionsTable.ComponentAt<BattalionRowController>(i),
                            batt));
        }

        public void HeroRowClicked(int index) {
            var heroId = Heroes.ElementAt(index).Id;
            if (CommandSelector != null && CommandSelector.HeroIsTargetable(heroId)) {
                CommandSelector.AddTargetedHero(heroId);
            }
            UpdateHeroSelections();
        }

        public void HeroRowRightClicked(int index) {
            var heroId = Heroes.ElementAt(index).Id;
            if (CommandSelector != null) { CommandSelector.RemoveTargetedHero(heroId); }
            UpdateHeroSelections();
        }

        public void LongHoverRowChanged(int? newIndex) {
            if (newIndex is {} index) {
                var heroId = Heroes.ElementAt(index).Id;
                popupPanelDetailsController.SetHero(Model.Heroes[heroId], Model);
                popupPanelBackstory.TextId = Model.Heroes[heroId].BackstoryTextId;
                popupPanel.SetActive(true);
            } else {
                popupPanel.SetActive(false);
            }
        }

        public void BattalionRowClicked(int index) {
            var battalionId = Battalions.ElementAt(index).Id;
            if (CommandSelector != null && CommandSelector.BattalionIsTargetable(battalionId)) {
                CommandSelector.AddTargetedBattalion(battalionId);
            }
            UpdateBattalionSelections();
        }

        public void BattalionRowRightClicked(int index) {
            var battalionId = Battalions.ElementAt(index).Id;
            if (CommandSelector != null) { CommandSelector.RemoveTargetedBattalion(battalionId); }
            UpdateBattalionSelections();
        }

        private void SetUpHeroesTable() {
            heroesTable.RowCount = HeroCount;

            Heroes.Each((hero, i) => {
                var row = heroesTable.ComponentAt<HeroRowController>(i);
                row.Hero = hero;
                SetHeroRowSelections(row, hero);
            });
        }

        private void SetUpBattalionsTable() {
            battalionsTable.RowCount = BattalionCount;

            Battalions.Each((battalion, i) => {
                var newRow = battalionsTable.ComponentAt<BattalionRowController>(i);
                newRow.Battalion = battalion;
                SetBattalionRowSelections(newRow, battalion);
            });
        }

        void Start() {
            panel.SetActive(Model != null);
            popupPanel.SetActive(false);
        }

        private bool HasProvinceInfo => CurrentProvince is { FullInfo : not null };

        private int HeroCount =>
                HasProvinceInfo ? CurrentProvince.FullInfo.RulingFactionHeroIds.Count : 0;
        private IEnumerable<HeroView> Heroes =>
                HasProvinceInfo ? CurrentProvince.FullInfo.RulingFactionHeroIds
                                          .Select(id => Model.Heroes[id])
                                          .OrderByDescending(h => h, HeroComparer.Shared)
                                : new List<HeroView>();

        private int BattalionCount =>
                HasProvinceInfo ? CurrentProvince.FullInfo.Battalions.Count : 0;
        private IEnumerable<BattalionView> Battalions =>
                HasProvinceInfo ? ProvinceUtils.OrderedBattalions(CurrentProvince)
                                : new List<BattalionView>();
    }
}