using System.Collections.Generic;
using System.Linq;
using common;
using Net.Eagle0.Eagle.Views;
using UnityEngine;
using UnityEngine.UI;
using FactionId = System.Int32;
using ProvinceId = System.Int32;

namespace eagle {
    public class MovingArmiesTableController : MonoBehaviour {
        public GameObject panel;

        public GameObject movingArmyPopupPanel;
        public EventBasedTable movingArmyPopupTable;

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

        public void MovingArmyLongHoverRowChanged(int? newIndex) {
            if (newIndex is {} index) {
                var movingArmy = MovingArmies.ElementAt(index);
                if (movingArmy.UnitDetails.Any()) {
                    ShowDetailedPopup(movingArmy);
                } else {
                    ShowSummaryPopup(movingArmy);
                }
            } else {
                movingArmyPopupPanel.SetActive(false);
            }
        }

        private void ShowDetailedPopup(IncomingArmyView movingArmy) {
            movingArmyPopupTable.RowCount = movingArmy.UnitDetails.Count;
            for (int i = 0; i < movingArmy.UnitDetails.Count; i++) {
                var details = movingArmy.UnitDetails[i];
                var row = movingArmyPopupTable.ComponentAt<MovingArmyPopupRowController>(i);
                row.SetHeroText(Model.Heroes[details.HeroId].NameTextId, "Hero");

                var battalion = details.Battalion;
                if (battalion != null) {
                    row.BattalionImage.texture =
                            EagleCommonTextures.Instance.BattalionType(details.Battalion.Type);
                    row.BattalionImage.gameObject.SetActive(true);
                    row.BattalionSize.text = details.Battalion.Size.ToString();
                    row.BattalionSize.gameObject.SetActive(true);
                } else {
                    row.BattalionImage.gameObject.SetActive(false);
                    row.BattalionSize.gameObject.SetActive(false);
                }
            }
            ResizeMovingArmyPopup(movingArmy.UnitDetails.Count);
            movingArmyPopupPanel.SetActive(true);
        }

        private void ShowSummaryPopup(IncomingArmyView movingArmy) {
            movingArmyPopupTable.RowCount = 1;
            var row = movingArmyPopupTable.ComponentAt<MovingArmyPopupRowController>(0);
            row.SetSummaryText(MovingArmySummaryText(movingArmy));
            row.BattalionImage.gameObject.SetActive(false);
            row.BattalionSize.gameObject.SetActive(false);
            ResizeMovingArmyPopup(1);
            movingArmyPopupPanel.SetActive(true);
        }

        private void ResizeMovingArmyPopup(int rowCount) {
            var rowHeight =
                    movingArmyPopupTable.rowPrefab.GetComponent<LayoutElement>().preferredHeight;
            var contentLayout =
                    movingArmyPopupTable.contentViewTransform.GetComponent<LayoutGroup>();
            var popupLayout = movingArmyPopupPanel.GetComponent<LayoutGroup>();

            var contentHeight = rowCount * rowHeight + contentLayout.padding.vertical;
            ((RectTransform)movingArmyPopupTable.contentViewTransform)
                    .SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, contentHeight);

            var popupHeight = contentHeight + popupLayout.padding.vertical;
            movingArmyPopupPanel.GetComponent<RectTransform>().SetSizeWithCurrentAnchors(
                    RectTransform.Axis.Vertical,
                    popupHeight);
        }

        private static string MovingArmySummaryText(IncomingArmyView movingArmy) {
            if (movingArmy.HeroCount == 0 && movingArmy.TroopCount == 0) {
                var supplies = new List<string>();
                if (movingArmy.Food != 0) supplies.Add($"{movingArmy.Food} food");
                if (movingArmy.Gold != 0) supplies.Add($"{movingArmy.Gold} gold");
                return supplies.Any() ? string.Join(", ", supplies) : "Supplies";
            }

            return $"{movingArmy.HeroCount} {Pluralize("hero", movingArmy.HeroCount)}, " +
                   $"{movingArmy.TroopCount} {Pluralize("troop", movingArmy.TroopCount)}";
        }

        private static string Pluralize(string noun, int count) {
            return count == 1 ? noun : $"{noun}s";
        }

        public void MovingArmyHoverRowChanged(int? newIndex) {
            if (newIndex is {} index) {
                var movingArmy = MovingArmies.ElementAt(index);
                mapController.OverrideTargetedProvinces = new List<ProvinceId> {
                    movingArmy.OriginProvinceId,
                    movingArmy.DestinationProvinceId
                };
            } else {
                mapController.OverrideTargetedProvinces = new List<ProvinceId>();
            }
        }

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

        public EventBasedTable movingArmiesTable;

        public MapController mapController;

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

        private void SetUpMovingArmiesTable() {
            movingArmiesTable.RowCount = MovingArmiesCount;

            MovingArmies.Each((army, i) => {
                var newRow = movingArmiesTable.ComponentAt<MovingArmyTableRow>(i);
                if (army.FactionId == Model.PlayerId) {
                    newRow.Faction = null;
                } else {
                    newRow.Faction = Model.FactionName(army.FactionId);
                    if (Model.PlayerId is FactionId myFid) {
                        if (Model.ActiveFactions[myFid].FactionRelationships.First(
                                    fr => fr.TargetFactionId == army.FactionId)
                                    is FactionRelationshipView frv &&
                            frv.RelationshipLevel ==
                                    FactionRelationshipView.Types.RelationshipLevel.Ally) {
                            newRow.FactionColor = Color.blue;
                        } else {
                            newRow.FactionColor = Color.red;
                        }
                    }
                }
                newRow.HeroCount = army.HeroCount;
                newRow.TroopCount = army.TroopCount;
                newRow.Origin = Model.Provinces[army.OriginProvinceId].Name;
                var destination = Model.Provinces[army.DestinationProvinceId].Name;
                newRow.Destination =
                        army.IsRetreating ? $"{destination} (Retreating)" : destination;
                if (CurrentProvince != null && army.DestinationProvinceId == CurrentProvince.Id) {
                    newRow.DestinationColor = Color.blue;
                } else {
                    newRow.DestinationColor = Color.black;
                }

                newRow.Gold = army.Gold;
                newRow.Food = army.Food;
                newRow.Selected = false;
                newRow.Selectable = false;
                newRow.RightSelectable = false;
            });
        }

        public void ProvinceHovered(ProvinceId? pid) {
            // Highlight moving armies table
            // Check row count to avoid index out of range if data changed after table was built
            var rowCount = movingArmiesTable.RowCount;
            MovingArmies.Each((army, i) => {
                if (i >= rowCount) return;
                var row = movingArmiesTable.ComponentAt<MovingArmyTableRow>(i);
                if (army.DestinationProvinceId == pid || army.OriginProvinceId == pid) {
                    row.ShadeOn();
                } else {
                    row.ShadeOff();
                }
            });
        }

        void Start() {
            panel.SetActive(Model != null);
            PopupClipper.Ensure(movingArmyPopupPanel);
            movingArmyPopupPanel.SetActive(false);
        }

        private bool IsHostileFaction(FactionId fid) {
            if (Model.PlayerId is FactionId myFid) {
                if (myFid == fid) return false;

                var fr = Model.MaybeDestroyedFaction(myFid).FactionRelationships.FirstOrDefault(
                        fr => fr.TargetFactionId == fid);

                if (fr == null) return false;

                return fr.RelationshipLevel ==
                       FactionRelationshipView.Types.RelationshipLevel.Hostile;
            }

            return false;
        }

        private int MovingArmiesCount => MovingArmies.Count();
        private IEnumerable<IncomingArmyView> MovingArmies =>
                Model.Provinces.Values.SelectMany(p => p.KnownIncomingArmies)
                        .OrderByDescending(a => IsHostileFaction(a.FactionId))
                        .ThenByDescending(a => a.FactionId == Model.PlayerId)
                        .ThenBy(a => CurrentProvince != null &&
                                     a.DestinationProvinceId != CurrentProvince.Id)
                        .ThenByDescending(a => a.HeroCount);
    }
}
