using UnityEngine;

namespace eagle {
    /// <summary>
    /// Creates a flood/rain particle effect with falling raindrops and splashes.
    /// Uses province masking shader to clip particles to province boundaries.
    /// </summary>
    [RequireComponent(typeof(RectTransform))]
    public class FloodEffect : MonoBehaviour {
        [Header("Rain Settings")]
        public Texture2D rainTexture;
        public Material particleMaterial;  // Assign in prefab to ensure shader is in build
        public float rainEmitRate = 80f;   // More rain
        public float rainFallSpeed = 100f;
        public float rainLifetime = 2f;  // Longer lifetime
        public float rainSize = 5f;
        public float rainStretch = 4f;
        public Color rainColor = new Color(0.7f, 0.8f, 0.9f, 0.6f);

        [Header("Splash Settings")]
        public float splashEmitRate = 25f;  // More splashes
        public float splashLifetime = 0.6f;
        public float splashSize = 10f;
        public Color splashColor = new Color(0.7f, 0.85f, 1f, 0.4f);

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

        private ParticleSystem _rainSystem;
        private ParticleSystem _splashSystem;
        private Material _rainMaterial;
        private Material _splashMaterial;
        private RectTransform _mapContainer;
        private Canvas _canvas;
        private Vector3 _baseRainShapeScale;
        private Vector3 _baseRainShapePosition;
        private float _baseSplashRadius;
        private float _baseRainEmitRate;
        private float _baseSplashEmitRate;
        private float _lastZoom = 1f;

        void Awake() { SetupParticleSystems(); }

        private void SetupParticleSystems() {
            // Create splash first (renders behind rain)
            var splashObj = new GameObject("SplashEffect");
            splashObj.transform.SetParent(transform, false);
            _splashSystem = splashObj.AddComponent<ParticleSystem>();
            SetupSplashSystem();

            // Create rain particle system
            var rainObj = new GameObject("RainEffect");
            rainObj.transform.SetParent(transform, false);
            _rainSystem = rainObj.AddComponent<ParticleSystem>();
            SetupRainSystem();
        }

        private void SetupRainSystem() {
            var main = _rainSystem.main;
            main.playOnAwake = true;
            main.loop = true;
            main.startLifetime = rainLifetime;
            main.startSpeed = 0f;
            main.startSize = rainSize;
            main.startColor = rainColor;
            main.startRotation = 0f;
            main.simulationSpace = ParticleSystemSimulationSpace.Local;
            main.scalingMode = ParticleSystemScalingMode.Hierarchy;
            main.maxParticles = 400;  // More particles for coverage

            var emission = _rainSystem.emission;
            emission.enabled = true;
            emission.rateOverTime = rainEmitRate;
            _baseRainEmitRate = rainEmitRate;

            // Emit across full province height - particles spawn at varying Y positions
            var shape = _rainSystem.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
            _baseRainShapeScale = shape.scale;
            _baseRainShapePosition = shape.position;

            // Fall downward with slight angle
            var velocityOverLifetime = _rainSystem.velocityOverLifetime;
            velocityOverLifetime.enabled = true;
            velocityOverLifetime.space = ParticleSystemSimulationSpace.Local;
            velocityOverLifetime.x = new ParticleSystem.MinMaxCurve(-5f, -5f);
            velocityOverLifetime.y = new ParticleSystem.MinMaxCurve(-rainFallSpeed, -rainFallSpeed);
            velocityOverLifetime.z = new ParticleSystem.MinMaxCurve(0f, 0f);

            // Fade in at top, stay visible
            var colorOverLifetime = _rainSystem.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.9f),
                        new GradientAlphaKey(0.5f, 1f)
                    });
            colorOverLifetime.color = new ParticleSystem.MinMaxGradient(gradient);

            var renderer = _rainSystem.GetComponent<ParticleSystemRenderer>();
            if (renderer != null) {
                renderer.renderMode = ParticleSystemRenderMode.Stretch;
                renderer.lengthScale = rainStretch;
                renderer.velocityScale = 0f;

                // Use provided material if available (ensures shader is in build)
                if (particleMaterial != null) {
                    _rainMaterial = new Material(particleMaterial);
                    _rainMaterial.renderQueue = 3000;
                    if (rainTexture != null) { _rainMaterial.mainTexture = rainTexture; }
                    renderer.material = _rainMaterial;
                } else {
                    // Fallback for editor testing
                    string[] shaderNames = {
                        "Eagle/ProvinceParticle",
                        "Universal Render Pipeline/Particles/Unlit",
                        "Particles/Standard Unlit",
                        "Legacy Shaders/Particles/Alpha Blended"
                    };

                    Shader shader = null;
                    foreach (var name in shaderNames) {
                        shader = Shader.Find(name);
                        if (shader != null) break;
                    }

                    if (shader != null) {
                        _rainMaterial = new Material(shader);
                        _rainMaterial.renderQueue = 3000;
                        if (rainTexture != null) { _rainMaterial.mainTexture = rainTexture; }
                        renderer.material = _rainMaterial;
                    } else {
                        Debug.LogWarning("FloodEffect: No particle shader found");
                    }
                }
                renderer.sortingOrder = 101;
            }
        }

        private void SetupSplashSystem() {
            var main = _splashSystem.main;
            main.playOnAwake = true;
            main.loop = true;
            main.startLifetime = splashLifetime;
            main.startSpeed = new ParticleSystem.MinMaxCurve(5f, 15f);
            main.startSize = new ParticleSystem.MinMaxCurve(splashSize * 0.5f, splashSize);
            main.startColor = splashColor;
            main.simulationSpace = ParticleSystemSimulationSpace.Local;
            main.scalingMode = ParticleSystemScalingMode.Hierarchy;
            main.maxParticles = 150;  // More splashes
            main.gravityModifier = 2f;

            var emission = _splashSystem.emission;
            emission.enabled = true;
            emission.rateOverTime = splashEmitRate;
            _baseSplashEmitRate = splashEmitRate;

            // Emit from ground area - large radius since shader masks
            var shape = _splashSystem.shape;
            shape.enabled = true;
            shape.shapeType = ParticleSystemShapeType.Circle;
            shape.radius = 60f;  // Larger splash area
            _baseSplashRadius = shape.radius;
            shape.rotation = new Vector3(-90f, 0f, 0f);
            shape.arc = 180f;
            shape.arcMode = ParticleSystemShapeMultiModeValue.Random;

            // Quick fade out
            var colorOverLifetime = _splashSystem.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(0.8f, 0f),
                        new GradientAlphaKey(0f, 1f)
                    });
            colorOverLifetime.color = new ParticleSystem.MinMaxGradient(gradient);

            // Shrink as they fade
            var sizeOverLifetime = _splashSystem.sizeOverLifetime;
            sizeOverLifetime.enabled = true;
            sizeOverLifetime.size = new ParticleSystem.MinMaxCurve(
                    1f,
                    new AnimationCurve(new Keyframe(0f, 1f), new Keyframe(1f, 0.2f)));

            var renderer = _splashSystem.GetComponent<ParticleSystemRenderer>();
            if (renderer != null) {
                // Use provided material if available (ensures shader is in build)
                if (particleMaterial != null) {
                    _splashMaterial = new Material(particleMaterial);
                    _splashMaterial.renderQueue = 3000;
                    renderer.material = _splashMaterial;
                } else {
                    // Fallback for editor testing
                    string[] shaderNames = {
                        "Eagle/ProvinceParticle",
                        "Universal Render Pipeline/Particles/Unlit",
                        "Particles/Standard Unlit",
                        "Legacy Shaders/Particles/Alpha Blended"
                    };

                    Shader shader = null;
                    foreach (var name in shaderNames) {
                        shader = Shader.Find(name);
                        if (shader != null) break;
                    }

                    if (shader != null) {
                        _splashMaterial = new Material(shader);
                        _splashMaterial.renderQueue = 3000;
                        renderer.material = _splashMaterial;
                    }
                }
                renderer.sortingOrder = 100;
            }
        }

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

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

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

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

        private void UpdateMapBounds() {
            if (_mapContainer == 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);
            if (_rainMaterial != null) { _rainMaterial.SetVector("_MapBounds", mapBounds); }
            if (_splashMaterial != null) { _splashMaterial.SetVector("_MapBounds", mapBounds); }
        }

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

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

            float inverseZoom = 1f / zoom;

            // Counter-scale rain system
            if (_rainSystem != null) {
                _rainSystem.transform.localScale = Vector3.one * inverseZoom;
                var shape = _rainSystem.shape;
                shape.scale = _baseRainShapeScale * zoom;
                shape.position = _baseRainShapePosition * zoom;
                var emission = _rainSystem.emission;
                emission.rateOverTime = _baseRainEmitRate * zoom * zoom;
            }

            // Counter-scale splash system
            if (_splashSystem != null) {
                _splashSystem.transform.localScale = Vector3.one * inverseZoom;
                var shape = _splashSystem.shape;
                shape.radius = _baseSplashRadius * zoom;
                var emission = _splashSystem.emission;
                emission.rateOverTime = _baseSplashEmitRate * zoom * zoom;
            }
        }

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