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

namespace eagle {
    public class MapController : MonoBehaviour {
        public EagleGameController eagleGameController;

        public RawImage mapBWImage;
        public List<RawImage> provinceImagesList;

        public TMP_Text provinceNameText;
        public TMP_Text provinceOwnerText;

        public bool Enabled { get; set; }

        private void SetDefaultProvinceColor(ProvinceId provinceId) {
            SetProvinceColor(provinceId, ColorForProvince(Model.Provinces[provinceId]));
        }

        public void ReloadFactionDisplaySetting() {
            RefreshHoveredProvinceDisplay(_previouslyHoveredProvinceId);
        }

        private void SetProvinceColor(ProvinceId provinceId, Color color) {
            var image = ImageForProvince(provinceId);
            if (!image.texture) {
                Texture2D texture = new Texture2D(1, 1);
                texture.wrapMode = TextureWrapMode.Repeat;
                image.texture = texture;
            }

            Texture2D t2d = (Texture2D)image.texture;
            t2d.SetPixel(0, 0, color);
            t2d.Apply();
        }

        private ProvinceId? _selectedProvinceId;
        public ProvinceId? SelectedProvinceId {
            get => _selectedProvinceId;
            set {
                if (_selectedProvinceId is ProvinceId provinceId) {
                    SetDefaultProvinceColor(provinceId);
                }
                _selectedProvinceId = value;
                eagleGameController.ProvinceWasSelected(value);
                SetUpCenterText(value, Color.black);
            }
        }

        private List<ProvinceId> _targetedProvinces = new List<ProvinceId>();
        public List<ProvinceId> TargetedProvinces {
            get => _targetedProvinces;
            set {
                if (value == null) { value = new List<ProvinceId>(); }
                if (!Enumerable.SequenceEqual(_targetedProvinces, value)) {
                    foreach (ProvinceId pid in _targetedProvinces) { SetDefaultProvinceColor(pid); }

                    _targetedProvinces = new List<ProvinceId>(value);
                }
            }
        }

        private List<ProvinceId> _overrideTargetedProvinces = new List<ProvinceId>();
        public IList<ProvinceId> OverrideTargetedProvinces {
            get => _overrideTargetedProvinces;
            set {
                if (value == null) { value = new List<ProvinceId>(); }
                if (!Enumerable.SequenceEqual(_overrideTargetedProvinces, value)) {
                    foreach (ProvinceId pid in _overrideTargetedProvinces) {
                        SetDefaultProvinceColor(pid);
                    }

                    _overrideTargetedProvinces = new List<ProvinceId>(value);
                }
            }
        }

        public Action<List<ProvinceId>> targetedProvincesChangedCallback;
        public Action<ProvinceId?> hoveredProvinceChangedCallback;
        private List<ProvinceId> _provincesWithCommands = new List<ProvinceId>();
        public List<ProvinceId> ProvincesWithCommands {
            get => _provincesWithCommands;
            set {
                if (!value.SequenceEqual(_provincesWithCommands)) {
                    foreach (var pid in _provincesWithCommands) { SetDefaultProvinceColor(pid); }
                    _provincesWithCommands = value;
                }
            }
        }

        private IGameModel _model;
        public IGameModel Model {
            get => _model;
            set {
                _model = value;

                if (value == null) { return; }

                foreach (var kv in _model.Provinces) { SetDefaultProvinceColor(kv.Value.Id); }

                foreach (var province in _model.Provinces.Values) {
                    SetDefaultProvinceColor(province.Id);
                }

                eagleGameController.ProvinceWasSelected(_selectedProvinceId);
            }
        }
        private RawImage ImageForProvince(ProvinceId id) => provinceImagesList[id - 1];

        public TextAsset rawGray;

        private int _imageWidth;
        private int _imageHeight;

        private readonly Color _selectionColor = Color.grey;
        private readonly Color _targetColor = Color.red;
        private readonly Color _commandAvailableColor = Color.blue;
        private readonly Color _hoverColor = new Color(0, 0, 0.5f, 0.5f);

        private byte[] _mapIdBytes;
        ProvinceId? _previouslyHoveredProvinceId;

        private Color ColorForProvince(ProvinceView province) {
            var color =
                    PlayerColors.LightPlayerColor(province.RulingFactionId.GetValueOrDefault(0));
            if (province.RulingFactionId.HasValue && province.FullInfo != null &&
                province.FullInfo.Support != null && province.FullInfo.Support.Stat < 40) {
                color = PlayerColors.MutedPlayerColor(
                        province.RulingFactionId.GetValueOrDefault(0));
            }

            return color;
        }

        void Start() {
            _mapIdBytes = rawGray.bytes;
            _imageWidth = mapBWImage.texture.width;
            _imageHeight = mapBWImage.texture.height;
            Enabled = true;
            _previouslyHoveredProvinceId = null;
        }

        int? ProvinceFromPoint(Vector2 point) {
            var mousePosition = new Vector2(point.x, Screen.height - point.y);
            var mapRect = gameObject.GetComponentInParent<PanelPositions>().MapRect;

            var relativeX = (int)((mousePosition.x - mapRect.x) * _imageWidth / mapRect.width);
            var relativeY =
                    (int)(_imageHeight -
                          (mousePosition.y - mapRect.y) * _imageHeight / mapRect.height);

            if (relativeX < 0 || relativeX >= _imageWidth || relativeY < 0 ||
                relativeY >= _imageHeight) {
                return null;
            }

            var provinceId = _mapIdBytes[relativeY * _imageWidth + relativeX];
            if (provinceId == 0 || provinceId == 0xFF) { return null; }
            return provinceId;
        }

        private void RefreshHoveredProvinceDisplay(ProvinceId? maybeHoveredProvinceId) {
            if (maybeHoveredProvinceId is ProvinceId hoveredProvinceId) {
                SetUpCenterText(hoveredProvinceId, _hoverColor);
            } else {
                SetUpCenterText(SelectedProvinceId, Color.black);
            }
        }

        void Update() {
            if (Model == null || Model.Provinces == null || Model.Provinces.Count == 0) { return; }

            var maybeHoveredProvinceId = ProvinceFromPoint(Input.mousePosition);
            if (Model != null && maybeHoveredProvinceId != _previouslyHoveredProvinceId) {
                _previouslyHoveredProvinceId = maybeHoveredProvinceId;
                hoveredProvinceChangedCallback.Invoke(maybeHoveredProvinceId);
                RefreshHoveredProvinceDisplay(maybeHoveredProvinceId);
            }

            if (OverrideTargetedProvinces.Any()) {
                if (SelectedProvinceId is ProvinceId sPid) { SetDefaultProvinceColor(sPid); }
                foreach (ProvinceId tPid in TargetedProvinces) { SetDefaultProvinceColor(tPid); }
                foreach (var commandProvince in ProvincesWithCommands) {
                    SetDefaultProvinceColor(commandProvince);
                }

                foreach (var pid in OverrideTargetedProvinces) {
                    FlashProvince(pid, _targetColor, 0.25f);
                }
            } else {
                if (SelectedProvinceId is ProvinceId sPid) {
                    FlashProvince(sPid, _selectionColor, 1.0f);
                }
                foreach (ProvinceId tPid in TargetedProvinces) {
                    FlashProvince(tPid, _targetColor, 0.25f);
                }
                foreach (var commandProvince in ProvincesWithCommands) {
                    FlashProvince(commandProvince, _commandAvailableColor, 0.5f);
                }
            }
        }

        private void FlashProvince(ProvinceId provinceId, Color flashColor, float duration) {
            SetProvinceColor(
                    provinceId,
                    Color.Lerp(
                            ColorForProvince(Model.Provinces[provinceId]),
                            flashColor,
                            Mathf.PingPong(Time.time, duration)));
        }

        public void OnLeftClick(Vector2 position) {
            SelectedProvinceId = ProvinceFromPoint(position);
        }

        public void OnRightClick(Vector2 position) {
            if (ProvinceFromPoint(position) is ProvinceId pid) {
                TargetedProvinces = new List<ProvinceId> { pid };
            } else {
                TargetedProvinces.Clear();
            }
            targetedProvincesChangedCallback.Invoke(TargetedProvinces);
        }

        void SetUpCenterText(ProvinceId? maybeProvinceId, Color color) {
            provinceNameText.color = color;
            provinceOwnerText.color = color;
            if (maybeProvinceId is ProvinceId pid) {
                var province = Model.Provinces[pid];
                provinceNameText.text = province.Name;

                if (province.RulingFactionId is FactionId fid) {
                    provinceOwnerText.text = Model.FactionName(fid);
                } else {
                    provinceOwnerText.text = "";
                }
            } else {
                provinceNameText.text = "";
                provinceOwnerText.text = "";
            }
        }
    }
}
