using System.Collections.Generic;
using Net.Eagle0.Eagle.Common;
using Net.Eagle0.Eagle.Views;
using UnityEngine;
using UnityEngine.UI;
using ProvinceId = System.Int32;

namespace eagle {
    public class ProvinceWeatherController : MonoBehaviour {
        [Header("References")]
        public MapController mapController;

        [Header("Effect Materials")]
        public Material blizzardMaterial;
        public Material floodMaterial;
        public Material droughtMaterial;

        private Dictionary<ProvinceId, ProvinceEvent.SealedValueOneofCase> _activeEffects = new();
        private Dictionary<ProvinceId, GameObject> _overlayObjects = new();
        private Dictionary<ProvinceId, Material> _instancedMaterials = new();

        public void UpdateWeatherEffects(IGameModel model) {
            if (model?.Provinces == null) { return; }

            var toRemove = new List<ProvinceId>();
            foreach (var kvp in _activeEffects) {
                if (!model.Provinces.ContainsKey(kvp.Key) ||
                    !HasWeatherEvent(model.Provinces[kvp.Key], kvp.Value)) {
                    DisableEffect(kvp.Key);
                    toRemove.Add(kvp.Key);
                }
            }
            foreach (var id in toRemove) { _activeEffects.Remove(id); }

            foreach (var province in model.Provinces.Values) {
                var weatherEvent = GetPriorityWeatherEvent(province);
                if (weatherEvent != ProvinceEvent.SealedValueOneofCase.None) {
                    if (!_activeEffects.ContainsKey(province.Id) ||
                        _activeEffects[province.Id] != weatherEvent) {
                        EnableEffect(province.Id, weatherEvent);
                        _activeEffects[province.Id] = weatherEvent;
                    }
                }
            }
        }

        private ProvinceEvent.SealedValueOneofCase GetPriorityWeatherEvent(ProvinceView province) {
            foreach (var evt in province.KnownEvents) {
                if (evt.SealedValueCase == ProvinceEvent.SealedValueOneofCase.BlizzardEvent) {
                    return ProvinceEvent.SealedValueOneofCase.BlizzardEvent;
                }
            }
            foreach (var evt in province.KnownEvents) {
                if (evt.SealedValueCase == ProvinceEvent.SealedValueOneofCase.FloodEvent) {
                    return ProvinceEvent.SealedValueOneofCase.FloodEvent;
                }
            }
            foreach (var evt in province.KnownEvents) {
                if (evt.SealedValueCase == ProvinceEvent.SealedValueOneofCase.DroughtEvent) {
                    return ProvinceEvent.SealedValueOneofCase.DroughtEvent;
                }
            }
            return ProvinceEvent.SealedValueOneofCase.None;
        }

        private bool HasWeatherEvent(
                ProvinceView province,
                ProvinceEvent.SealedValueOneofCase eventType) {
            foreach (var evt in province.KnownEvents) {
                if (evt.SealedValueCase == eventType) { return true; }
            }
            return false;
        }

        private RawImage GetProvinceImage(ProvinceId provinceId) {
            if (mapController?.provinceImagesList == null || provinceId < 1 ||
                provinceId > mapController.provinceImagesList.Count) {
                return null;
            }
            return mapController.provinceImagesList[provinceId - 1];
        }

        private void EnableEffect(
                ProvinceId provinceId,
                ProvinceEvent.SealedValueOneofCase eventType) {
            var provinceImage = GetProvinceImage(provinceId);
            if (provinceImage == null) { return; }

            DisableEffect(provinceId);

            Material baseMat = eventType switch {
                ProvinceEvent.SealedValueOneofCase.BlizzardEvent => blizzardMaterial,
                ProvinceEvent.SealedValueOneofCase.FloodEvent => floodMaterial,
                ProvinceEvent.SealedValueOneofCase.DroughtEvent => droughtMaterial,
                _ => null
            };
            if (baseMat == null) { return; }

            var overlayGO = new GameObject($"WeatherOverlay_{provinceId}");
            overlayGO.transform.SetParent(provinceImage.transform, false);

            var rect = overlayGO.AddComponent<RectTransform>();
            rect.anchorMin = Vector2.zero;
            rect.anchorMax = Vector2.one;
            rect.offsetMin = Vector2.zero;
            rect.offsetMax = Vector2.zero;

            var overlay = overlayGO.AddComponent<RawImage>();
            overlay.raycastTarget = false;

            var mat = new Material(baseMat);
            var provinceMaterial = provinceImage.material;
            if (provinceMaterial != null && provinceMaterial.HasProperty("_Mask")) {
                mat.SetTexture("_Mask", provinceMaterial.GetTexture("_Mask"));
            }

            overlay.material = mat;
            _overlayObjects[provinceId] = overlayGO;
            _instancedMaterials[provinceId] = mat;
        }

        private void DisableEffect(ProvinceId provinceId) {
            if (_overlayObjects.TryGetValue(provinceId, out var overlayGO)) {
                Destroy(overlayGO);
                _overlayObjects.Remove(provinceId);
            }

            if (_instancedMaterials.TryGetValue(provinceId, out var mat)) {
                Destroy(mat);
                _instancedMaterials.Remove(provinceId);
            }
        }

        private void OnDestroy() {
            foreach (var go in _overlayObjects.Values) {
                if (go != null) { Destroy(go); }
            }
            _overlayObjects.Clear();

            foreach (var mat in _instancedMaterials.Values) {
                if (mat != null) { Destroy(mat); }
            }
            _instancedMaterials.Clear();
        }
    }
}
