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

namespace eagle {
    /// <summary>
    /// Manages drought effects for provinces.
    /// Spawns sun icons at province centers when DroughtEvent is active.
    /// </summary>
    public class ProvinceDroughtController : MonoBehaviour {
        [Header("References")]
        public RectTransform mapContainer;
        public GameObject droughtEffectPrefab;
        public ProvinceIDLoader provinceIDLoader;

        [Header("Spawn Offset")]
        [Tooltip("Vertical offset as fraction of map height (positive = above center for sun)")]
        public float verticalOffsetFraction = 0.02f;

        private Dictionary<ProvinceId, Vector2> _provinceCentroids = new();
        private Dictionary<ProvinceId, float> _provinceWidths = new();
        private Dictionary<ProvinceId, GameObject> _activeEffects = new();

        void Awake() { provinceIDLoader.OnMapLoaded += LoadCentroids; }

        private void LoadCentroids() {
            var data = JsonUtility.FromJson<CentroidsData>(provinceIDLoader.CentroidsJsonText);
            if (data?.provinces == null) {
                Debug.LogWarning("ProvinceDroughtController: Failed to parse centroids.json");
                return;
            }

            foreach (var province in data.provinces) {
                _provinceCentroids[province.id] =
                        new Vector2(province.centroid_x, province.centroid_y);
                _provinceWidths[province.id] = province.perpendicular_width;
            }
        }

        public void UpdateDroughtEffects(IGameModel model) {
            if (_provinceCentroids.Count == 0 && provinceIDLoader.CentroidsJsonText != null) {
                LoadCentroids();
            }
            if (model?.Provinces == null) { return; }

            var provincesWithDrought = new HashSet<ProvinceId>();
            foreach (var province in model.Provinces.Values) {
                if (HasDroughtEvent(province)) { provincesWithDrought.Add(province.Id); }
            }

            var toRemove = new List<ProvinceId>();
            foreach (var kvp in _activeEffects) {
                if (!provincesWithDrought.Contains(kvp.Key)) {
                    Destroy(kvp.Value);
                    toRemove.Add(kvp.Key);
                }
            }
            foreach (var id in toRemove) { _activeEffects.Remove(id); }

            foreach (var provinceId in provincesWithDrought) {
                if (!_activeEffects.ContainsKey(provinceId)) { SpawnDroughtEffect(provinceId); }
            }
        }

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

        private void SpawnDroughtEffect(ProvinceId provinceId) {
            if (droughtEffectPrefab == null || mapContainer == null) { return; }
            if (!_provinceCentroids.TryGetValue(provinceId, out Vector2 centroid)) { return; }

            int mapWidth = provinceIDLoader.mapWidth;
            int mapHeight = provinceIDLoader.mapHeight;

            var effect = Instantiate(droughtEffectPrefab, mapContainer);
            effect.name = $"Drought_Province{provinceId}";

            Canvas.ForceUpdateCanvases();
            var containerSize = mapContainer.rect.size;
            if (containerSize.x < 1f || containerSize.y < 1f) {
                containerSize = new Vector2(mapWidth, mapHeight);
            }

            var rectTransform = effect.GetComponent<RectTransform>();
            if (rectTransform != null) {
                var normalizedX = centroid.x / mapWidth;
                var normalizedY = centroid.y / mapHeight;

                rectTransform.anchorMin = Vector2.zero;
                rectTransform.anchorMax = Vector2.zero;
                rectTransform.pivot = new Vector2(0.5f, 0.5f);
                var yOffset = verticalOffsetFraction * containerSize.y;
                rectTransform.anchoredPosition = new Vector2(
                        normalizedX * containerSize.x,
                        normalizedY * containerSize.y + yOffset);
            }

            _activeEffects[provinceId] = effect;
        }

        void OnDestroy() {
            foreach (var effect in _activeEffects.Values) {
                if (effect != null) { Destroy(effect); }
            }
            _activeEffects.Clear();
        }

        [Serializable]
        private class CentroidsData {
            public ProvinceCentroid[] provinces;
        }

        [Serializable]
        private class ProvinceCentroid {
            public int id;
            public string name;
            public float centroid_x;
            public float centroid_y;
            public float perpendicular_width;
        }
    }
}
