using UnityEngine;

namespace eagle {
    /// <summary>
    /// Creates a blizzard particle effect with falling snowflakes.
    /// Uses province masking shader to clip particles to province boundaries.
    /// </summary>
    [RequireComponent(typeof(RectTransform))]
    public class BlizzardEffect : MonoBehaviour {
        [Header("Snowflake Settings")]
        public Texture2D snowflakeTexture;
        public Material particleMaterial;  // Assign in prefab to ensure shader is in build
        public float snowEmitRate = 45f;
        public float snowFallSpeed = 50f;
        public float snowLifetime = 4f;  // Longer lifetime
        public float snowSize = 10f;     // Slightly larger
        public float snowDrift = 15f;    // More drift
        public Color snowColor = Color.white;

        [Header("Wind Settings")]
        public float windStrength = 5f;
        public float windVariation = 3f;

        [Header("Province Masking")]
        public Texture2D provinceIdMap;
        public int targetProvinceId;

        private ParticleSystem _snowSystem;
        private Material _material;
        private RectTransform _mapContainer;
        private Canvas _canvas;
        private Vector3 _baseShapeScale;
        private Vector3 _baseShapePosition;
        private float _baseEmitRate;
        private float _lastZoom = 1f;

        void Awake() { SetupParticleSystems(); }

        private void SetupParticleSystems() {
            var snowObj = new GameObject("SnowEffect");
            snowObj.transform.SetParent(transform, false);
            _snowSystem = snowObj.AddComponent<ParticleSystem>();
            SetupSnowSystem();
        }

        private void SetupSnowSystem() {
            var main = _snowSystem.main;
            main.playOnAwake = true;
            main.loop = true;
            main.startLifetime = snowLifetime;
            main.startSpeed = 0f;
            main.startSize = new ParticleSystem.MinMaxCurve(snowSize * 0.5f, snowSize);
            main.startColor = snowColor;
            main.startRotation = new ParticleSystem.MinMaxCurve(0f, Mathf.PI * 2f);
            main.simulationSpace = ParticleSystemSimulationSpace.Local;
            main.scalingMode = ParticleSystemScalingMode.Hierarchy;
            main.maxParticles = 900;

            var emission = _snowSystem.emission;
            emission.enabled = true;
            emission.rateOverTime = snowEmitRate;
            _baseEmitRate = snowEmitRate;

            // Emit across full province height - particles spawn at varying Y positions
            var shape = _snowSystem.shape;
            shape.enabled = true;
            shape.shapeType = ParticleSystemShapeType.Box;
            shape.scale = new Vector3(150f, 150f, 1f);  // Wide and very tall emission area
            shape.position = new Vector3(0f, 40f, 0f);  // Centered above effect origin

            // Store base values for zoom compensation
            _baseShapeScale = shape.scale;
            _baseShapePosition = shape.position;

            // Fall downward with horizontal drift
            var velocityOverLifetime = _snowSystem.velocityOverLifetime;
            velocityOverLifetime.enabled = true;
            velocityOverLifetime.space = ParticleSystemSimulationSpace.Local;
            velocityOverLifetime.x = new ParticleSystem.MinMaxCurve(
                    -snowDrift - windStrength,
                    snowDrift + windStrength);
            velocityOverLifetime.y = new ParticleSystem.MinMaxCurve(-snowFallSpeed, -snowFallSpeed);
            velocityOverLifetime.z = new ParticleSystem.MinMaxCurve(0f, 0f);

            // Gentle rotation as they fall
            var rotationOverLifetime = _snowSystem.rotationOverLifetime;
            rotationOverLifetime.enabled = true;
            rotationOverLifetime.z = new ParticleSystem.MinMaxCurve(-0.5f, 0.5f);

            // Use noise for fluttering motion
            var noise = _snowSystem.noise;
            noise.enabled = true;
            noise.strength = windVariation;
            noise.frequency = 0.5f;
            noise.scrollSpeed = 0.2f;
            noise.damping = false;

            // Fade in and out
            var colorOverLifetime = _snowSystem.colorOverLifetime;
            colorOverLifetime.enabled = true;
            var gradient = new Gradient();
            gradient.SetKeys(
                    new GradientColorKey[] {
                        new GradientColorKey(Color.white, 0f),
                        new GradientColorKey(Color.white, 1f)
                    },
                    new GradientAlphaKey[] {
                        new GradientAlphaKey(0f, 0f),
                        new GradientAlphaKey(1f, 0.1f),
                        new GradientAlphaKey(1f, 0.8f),
                        new GradientAlphaKey(0f, 1f)
                    });
            colorOverLifetime.color = new ParticleSystem.MinMaxGradient(gradient);

            var renderer = _snowSystem.GetComponent<ParticleSystemRenderer>();
            if (renderer != null) {
                _material = new Material(particleMaterial);
                _material.renderQueue = 3000;
                if (snowflakeTexture != null) { _material.mainTexture = snowflakeTexture; }
                renderer.material = _material;
                renderer.sortingOrder = 100;
            }
        }

        public void SetProvinceId(int provinceId) {
            targetProvinceId = provinceId;
            if (_material != null) { _material.SetFloat("_TargetProvinceId", provinceId); }
        }

        public void SetProvinceIdMap(Texture2D idMap) {
            provinceIdMap = idMap;
            if (_material != null) { _material.SetTexture("_ProvinceIDMap", idMap); }
        }

        public void SetMapContainer(RectTransform container) {
            _mapContainer = container;
            _canvas = container?.GetComponentInParent<Canvas>();
        }

        void LateUpdate() {
            UpdateMapBounds();
            UpdateZoomCompensation();
        }

        private void UpdateMapBounds() {
            if (_mapContainer == null || _material == null) { return; }

            Vector3[] corners = new Vector3[4];
            _mapContainer.GetWorldCorners(corners);

            Camera cam = _canvas?.worldCamera ?? Camera.main;
            Vector3 screenBL, screenTR;
            if (_canvas != null && _canvas.renderMode == RenderMode.ScreenSpaceOverlay) {
                screenBL = corners[0];
                screenTR = corners[2];
            } else {
                screenBL = cam != null ? cam.WorldToScreenPoint(corners[0]) : corners[0];
                screenTR = cam != null ? cam.WorldToScreenPoint(corners[2]) : corners[2];
            }

            var mapBounds = new Vector4(
                    screenBL.x,
                    screenBL.y,
                    screenTR.x - screenBL.x,
                    screenTR.y - screenBL.y);
            _material.SetVector("_MapBounds", mapBounds);
        }

        private void UpdateZoomCompensation() {
            if (_mapContainer == null || _snowSystem == null) { return; }

            float zoom = _mapContainer.localScale.x;
            if (Mathf.Approximately(zoom, _lastZoom)) { return; }
            _lastZoom = zoom;

            // Counter-scale particle system to maintain screen-space appearance
            float inverseZoom = 1f / zoom;
            _snowSystem.transform.localScale = Vector3.one * inverseZoom;

            // Expand emission area to still cover the province
            var shape = _snowSystem.shape;
            shape.scale = _baseShapeScale * zoom;
            shape.position = _baseShapePosition * zoom;

            // Increase emission rate to maintain screen-space density (area scales as zoom²)
            var emission = _snowSystem.emission;
            emission.rateOverTime = _baseEmitRate * zoom * zoom;
        }

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