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

namespace eagle {
    /// <summary>
    /// Manages weather effects for provinces using a 256x1 lookup texture.
    /// Each pixel index corresponds to a province ID, with:
    /// - R channel: weather type (0=none, 0.25=blizzard, 0.5=flood, 0.75=drought)
    /// - A channel: intensity (0=off, 1=full)
    /// Note: Epidemic is handled separately by ProvinceEpidemicController with particle effects.
    /// </summary>
    public class ProvinceWeatherController : MonoBehaviour {
        [Header("Material")]
        public Material weatherMaterial;

        private Dictionary<ProvinceId, ProvinceEvent.SealedValueOneofCase> _activeEffects = new();
        private Texture2D _weatherLookup;
        private Color[] _weatherColors;
        private bool _dirty;

        // Weather type encodings (stored in R channel)
        // Note: Blizzard uses 3D particle effect only (ProvinceBlizzardController)
        private const float WeatherNone = 0f;
        private const float WeatherFlood = 0.5f;
        private const float WeatherDrought = 0.75f;

        void Awake() { InitializeWeatherLookup(); }

        private void InitializeWeatherLookup() {
            _weatherLookup = new Texture2D(256, 1, TextureFormat.RGBA32, false);
            _weatherLookup.filterMode = FilterMode.Point;
            _weatherLookup.wrapMode = TextureWrapMode.Clamp;

            _weatherColors = new Color[256];
            for (int i = 0; i < 256; i++) { _weatherColors[i] = Color.clear; }

            _weatherLookup.SetPixels(_weatherColors);
            _weatherLookup.Apply();

            if (weatherMaterial != null) {
                weatherMaterial.SetTexture("_WeatherLookup", _weatherLookup);
            }
        }

        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) {
            // Note: Blizzard uses 3D particle effect only (ProvinceBlizzardController)
            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;
                }
            }
            // Note: Epidemic is handled by ProvinceEpidemicController, not here
            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 void EnableEffect(
                ProvinceId provinceId,
                ProvinceEvent.SealedValueOneofCase eventType) {
            if (provinceId < 0 || provinceId > 255) { return; }

            float weatherType = eventType switch {
                ProvinceEvent.SealedValueOneofCase.FloodEvent => WeatherFlood,
                ProvinceEvent.SealedValueOneofCase.DroughtEvent => WeatherDrought,
                _ => WeatherNone
            };

            _weatherColors[provinceId] = new Color(weatherType, 0, 0, 1f);
            _dirty = true;
        }

        private void DisableEffect(ProvinceId provinceId) {
            if (provinceId < 0 || provinceId > 255) { return; }
            _weatherColors[provinceId] = Color.clear;
            _dirty = true;
        }

        void LateUpdate() {
            if (_dirty) {
                _weatherLookup.SetPixels(_weatherColors);
                _weatherLookup.Apply();
                _dirty = false;
            }
        }

        private void OnDestroy() {
            if (_weatherLookup != null) { Destroy(_weatherLookup); }
        }
    }
}
