

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

namespace com.al_arcade.shared
{
    public class SSParticleManager : MonoBehaviour
    {
        public static SSParticleManager Instance { get; private set; }

        [Header("Optional Prefabs (leave null for procedural)")]
        public ParticleSystem correctBurstPrefab;
        public ParticleSystem wrongBurstPrefab;
        public ParticleSystem confettiPrefab;
        public ParticleSystem sparksPrefab;
        public ParticleSystem starBurstPrefab;

        private Dictionary<string, ParticleSystem> _cache = new();

        private void Awake()
        {
            if (Instance != null && Instance != this)
            {
                Destroy(gameObject);
                return;
            }
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }

        public static SSParticleManager EnsureInstance()
        {
            if (Instance != null) return Instance;
            var go = new GameObject("[SSParticleManager]");
            Instance = go.AddComponent<SSParticleManager>();
            DontDestroyOnLoad(go);
            return Instance;
        }


        public void PlayCorrectBurst(Vector3 position)
        {
            if (correctBurstPrefab != null)
            {
                SpawnPrefab(correctBurstPrefab, position);
                return;
            }
            PlayProceduralBurst(position, SSColorPalette.Success,
                SSColorPalette.Accent, 30, 0.6f);
        }

        public void PlayWrongBurst(Vector3 position)
        {
            if (wrongBurstPrefab != null)
            {
                SpawnPrefab(wrongBurstPrefab, position);
                return;
            }
            PlayProceduralBurst(position, SSColorPalette.Danger,
                SSColorPalette.Warning, 20, 0.4f);
        }

        public void PlayConfetti(Vector3 position)
        {
            if (confettiPrefab != null)
            {
                SpawnPrefab(confettiPrefab, position);
                return;
            }
            PlayProceduralConfetti(position, 80);
        }

        public void PlaySparks(Vector3 position, Color color)
        {
            if (sparksPrefab != null)
            {
                SpawnPrefab(sparksPrefab, position);
                return;
            }
            PlayProceduralBurst(position, color, Color.white, 15, 0.3f);
        }

        public void PlayStarBurst(Vector3 position)
        {
            if (starBurstPrefab != null)
            {
                SpawnPrefab(starBurstPrefab, position);
                return;
            }
            PlayProceduralBurst(position, SSColorPalette.Accent,
                Color.white, 25, 0.8f);
        }

        public void PlayScreenConfetti()
        {
            if (Camera.main == null) return;
            Vector3 pos = Camera.main.transform.position +
                          Camera.main.transform.forward * 5f +
                          Vector3.up * 3f;
            PlayConfetti(pos);
        }


        private void PlayProceduralBurst(Vector3 pos, Color startColor,
            Color endColor, int count, float lifetime)
        {
            var go = new GameObject("SSParticle_Burst");
            go.transform.position = pos;
            var ps = go.AddComponent<ParticleSystem>();

            var main = ps.main;
            main.startLifetime = lifetime;
            main.startSpeed = new ParticleSystem.MinMaxCurve(2f, 6f);
            main.startSize = new ParticleSystem.MinMaxCurve(0.05f, 0.15f);
            main.startColor = new ParticleSystem.MinMaxGradient(startColor, endColor);
            main.gravityModifier = 1.5f;
            main.maxParticles = count;
            main.simulationSpace = ParticleSystemSimulationSpace.World;
            main.loop = false;
            main.playOnAwake = true;
            main.duration = 0.1f;

            var emission = ps.emission;
            emission.rateOverTime = 0;
            emission.SetBursts(new[] { new ParticleSystem.Burst(0f, (short)count) });

            var shape = ps.shape;
            shape.shapeType = ParticleSystemShapeType.Sphere;
            shape.radius = 0.2f;

            var sizeOverLife = ps.sizeOverLifetime;
            sizeOverLife.enabled = true;
            sizeOverLife.size = new ParticleSystem.MinMaxCurve(1f,
                new AnimationCurve(
                    new Keyframe(0f, 1f),
                    new Keyframe(1f, 0f)));


            var renderer = go.GetComponent<ParticleSystemRenderer>();
            renderer.material = GetParticleMaterial();

            ps.Play();
            Destroy(go, lifetime + 0.5f);
        }

        private void PlayProceduralConfetti(Vector3 pos, int count)
        {
            var go = new GameObject("SSParticle_Confetti");
            go.transform.position = pos;
            var ps = go.AddComponent<ParticleSystem>();

            var main = ps.main;
            main.startLifetime = new ParticleSystem.MinMaxCurve(2f, 4f);
            main.startSpeed = new ParticleSystem.MinMaxCurve(3f, 8f);
            main.startSize = new ParticleSystem.MinMaxCurve(0.08f, 0.2f);
            main.startRotation3D = true;
            main.startRotationX = new ParticleSystem.MinMaxCurve(0f, 360f * Mathf.Deg2Rad);
            main.startRotationY = new ParticleSystem.MinMaxCurve(0f, 360f * Mathf.Deg2Rad);
            main.startRotationZ = new ParticleSystem.MinMaxCurve(0f, 360f * Mathf.Deg2Rad);
            main.gravityModifier = 1.2f;
            main.maxParticles = count;
            main.simulationSpace = ParticleSystemSimulationSpace.World;
            main.loop = false;
            main.duration = 0.2f;


            var gradient = new Gradient();
            gradient.SetKeys(
                new[] {
                    new GradientColorKey(SSColorPalette.Accent, 0f),
                    new GradientColorKey(SSColorPalette.Primary, 0.25f),
                    new GradientColorKey(SSColorPalette.Success, 0.5f),
                    new GradientColorKey(SSColorPalette.Danger, 0.75f),
                    new GradientColorKey(SSColorPalette.Info, 1f)
                },
                new[] {
                    new GradientAlphaKey(1f, 0f),
                    new GradientAlphaKey(1f, 0.8f),
                    new GradientAlphaKey(0f, 1f)
                });
            main.startColor = new ParticleSystem.MinMaxGradient(gradient);

            var emission = ps.emission;
            emission.rateOverTime = 0;
            emission.SetBursts(new[] { new ParticleSystem.Burst(0f, (short)count) });

            var shape = ps.shape;
            shape.shapeType = ParticleSystemShapeType.Cone;
            shape.angle = 40f;
            shape.radius = 0.5f;

            var rotOverLife = ps.rotationOverLifetime;
            rotOverLife.enabled = true;
            rotOverLife.z = new ParticleSystem.MinMaxCurve(-180f * Mathf.Deg2Rad,
                180f * Mathf.Deg2Rad);

            var renderer = go.GetComponent<ParticleSystemRenderer>();
            renderer.material = GetParticleMaterial();
            renderer.renderMode = ParticleSystemRenderMode.Billboard;

            ps.Play();
            Destroy(go, 5f);
        }


        private void SpawnPrefab(ParticleSystem prefab, Vector3 pos)
        {
            var instance = Instantiate(prefab, pos, Quaternion.identity);
            var main = instance.main;
            float lifetime = main.startLifetime.constantMax;
            if (main.startLifetime.mode == ParticleSystemCurveMode.TwoConstants)
                lifetime = main.startLifetime.constantMax;
            Destroy(instance.gameObject, lifetime + main.duration + 1f);
        }

        private Material _cachedMat;
        private Material GetParticleMaterial()
        {
            if (_cachedMat != null) return _cachedMat;


            Shader shader = Shader.Find("Particles/Standard Unlit");
            if (shader == null) shader = Shader.Find("Universal Render Pipeline/Particles/Unlit");
            if (shader == null) shader = Shader.Find("Mobile/Particles/Alpha Blended");
            if (shader == null) shader = Shader.Find("Sprites/Default");
            if (shader == null) shader = Shader.Find("Unlit/Color");

            _cachedMat = new Material(shader);
            _cachedMat.SetFloat("_Mode", 2);
            return _cachedMat;
        }
    }
}
