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

namespace eagle {
    using ProvinceId = Int32;

    public class DominionPanelController : MonoBehaviour {
        public EventBasedTable table;
        public DisclosureTriangle disclosureToggle;

        public MapController mapController;

        enum SortKey {
            Name = 0,
            Support = 1,
            Commanders = 2,
            Battalions = 3,
            Troops = 4,
            Economy = 5,
            Agriculture = 6,
            Infrastructure = 7,
            Gold = 8,
            Food = 9,
            FreeHeroes = 10,
            Castles = 11,
        }

        private readonly Func<ProvinceView, String> _nameSortFunc = p => p.Name;

        private readonly Dictionary<SortKey, Func<ProvinceView, IComparable>> _sortFuncs = new() {
            { SortKey.Support, p => p.FullInfo.Support.Stat },
            { SortKey.Commanders, p => p.FullInfo.RulingFactionHeroIds.Count },
            { SortKey.Battalions, p => p.FullInfo.Battalions.Count },
            { SortKey.Troops, p => p.FullInfo.Battalions.Sum(b => b.Size) },
            { SortKey.Economy, p => p.FullInfo.Economy },
            { SortKey.Agriculture, p => p.FullInfo.Agriculture },
            { SortKey.Infrastructure, p => p.FullInfo.Infrastructure },
            { SortKey.Gold, p => p.FullInfo.Gold },
            { SortKey.Food, p => p.FullInfo.Food },
            { SortKey.FreeHeroes, p => p.FullInfo.UnaffiliatedHeroes.Count },
            { SortKey.Castles, p => p.FullInfo.CastleCount },
        };

        private SortKey _currentSortKey = SortKey.Name;
        private bool _ascending = false;

        private IGameModel _model;
        public IGameModel Model {
            set {
                _model = value;
                SetUpTable();
            }
        }

        public void ForceUpdate() { SetUpTable(); }

        private List<ProvinceView> SortedProvinces() {
            if (_model == null) { return new List<ProvinceView>(); }

            var unsorted = _model.Provinces.Values.Where(p => p.RulingFactionId == _model.PlayerId);

            if (_currentSortKey == SortKey.Name) {
                return _ascending ? unsorted.OrderBy(_nameSortFunc).ToList()
                                  : unsorted.OrderByDescending(_nameSortFunc).ToList();
            }

            var sortFunc = _sortFuncs[_currentSortKey];

            return _ascending ? unsorted.OrderBy(sortFunc).ToList()
                              : unsorted.OrderByDescending(sortFunc).ToList();
        }

        void SetUpTable() {
            var provinces = SortedProvinces();

            table.RowCount = provinces.Count;

            for (int i = 0; i < provinces.Count; i++) {
                var province = provinces[i];
                var hasCommands = _model.AvailableCommandsForProvince(province.Id).Any();
                table.ComponentAt<DominionTableRowController>(i).Set(
                        province.Id,
                        _model,
                        mapController.SelectedProvinceId == province.Id,
                        hasCommands);
            }
        }

        public void Sort(int key) {
            SortKey newKey = (SortKey)key;

            if (newKey == _currentSortKey) {
                _ascending = !_ascending;
            } else {
                _currentSortKey = newKey;
                _ascending = newKey == SortKey.Name;
            }

            SetUpTable();
        }

        // Start is called before the first frame update
        void Start() {
            _currentSortKey = SortKey.Name;
            _ascending = true;
        }

        private void OnEnable() {
            if (disclosureToggle != null) { disclosureToggle.isOn = true; }
        }

        // Update is called once per frame
        void Update() {
            if (Input.GetButtonUp("Toggle Dominion Table") && disclosureToggle != null) {
                disclosureToggle.isOn = !disclosureToggle.isOn;
            }
        }

        public void ProvinceHovered(ProvinceId? pid) {
            for (int i = 0; i < table.RowCount; i++) {
                table.ComponentAt<DominionTableRowController>(i).ShadeOff();
            }
            if (pid is ProvinceId provinceId) {
                var index = SortedProvinces().FindIndex(p => p.Id == provinceId);
                if (index != -1) { table.ComponentAt<DominionTableRowController>(index).ShadeOn(); }
            }
        }

        public void RowClicked(int provinceId) { mapController.SelectedProvinceId = provinceId; }

        public void RowHovered(int provinceId) {
            mapController.OverrideTargetedProvinces = new List<ProvinceId> { provinceId };
        }

        public void RowUnhovered() {
            mapController.OverrideTargetedProvinces = new List<ProvinceId>();
        }
    }
}