using UnityEngine;

namespace IndianOceanAssets.Engine2_5D
{
    /// <summary>
    /// 描边管理器 —— 自动为场景中所有 SpriteRenderer（排除挂载 LightSource 的物体）
    /// 创建一个使用 SpriteEchoOutline shader 的子物体，用于回声描边效果。
    ///
    /// 为什么需要子物体：
    /// - 精灵本体用原始材质（如 SpriteShader.shadergraph）渲染，在黑暗遮罩之下 → 黑暗中不可见
    /// - 描边用 SpriteEchoOutline 材质渲染，队列在黑暗遮罩之上（Transparent+200）→ 黑暗中可见
    /// - 同一个 SpriteRenderer 只能有一个材质，所以用子物体承载描边材质
    ///
    /// 使用方式：
    /// 1. 场景中创建空物体，挂上此脚本
    /// 2. 把使用 SpriteEchoOutline shader 的材质拖到 outlineMaterial 字段
    /// 3. 运行后自动为每个非光源精灵生成描边子物体
    /// 4. 场景中新增精灵后可右键组件 > Refresh Outlines 重新扫描
    /// </summary>
    public class EchoOutlineManager : MonoBehaviour
    {
        [Header("描边材质（使用 SpriteEchoOutline shader）")]
        [SerializeField] private Material outlineMaterial;

        [Header("过滤")]
        [Tooltip("只处理这些层的精灵（默认 Everything）")]
        [SerializeField] private LayerMask includeLayers = ~0;

        [Tooltip("勾选后，挂载 LightSource 的物体（含父级）不生成描边")]
        [SerializeField] private bool skipLightSources = true;

        private static readonly int EchoIntensityID = Shader.PropertyToID("_EchoOutlineIntensity");
        private static readonly int OutlineColorID  = Shader.PropertyToID("_OutlineColor");
        private static readonly int OutlineWidthID  = Shader.PropertyToID("_OutlineWidth");
        private static readonly int MainTexID       = Shader.PropertyToID("_MainTex");

        private readonly System.Collections.Generic.List<SpriteRenderer> _parentRenderers
            = new System.Collections.Generic.List<SpriteRenderer>();
        private readonly System.Collections.Generic.List<SpriteRenderer> _outlineRenderers
            = new System.Collections.Generic.List<SpriteRenderer>();

        private bool _renderersEnabled = false;

        private void Start()
        {
            RefreshList();
        }

        /// <summary>
        /// 重新扫描场景，为符合条件的精灵创建描边子物体。
        /// 场景中新增精灵后可调用（也有右键菜单）。
        /// </summary>
        [ContextMenu("Refresh Outlines")]
        public void RefreshList()
        {
            ClearOutlines();

            var all = FindObjectsByType<SpriteRenderer>(FindObjectsSortMode.None);
            foreach (var sr in all)
            {
                if (sr == null) continue;
                if ((includeLayers.value & (1 << sr.gameObject.layer)) == 0) continue;
                if (skipLightSources && sr.GetComponentInParent<LightSource>() != null) continue;

                // 跳过已经是描边子物体的（避免重复）。用 sharedMaterial 避免实例化父级材质
                if (sr.sharedMaterial != null && sr.sharedMaterial.shader != null
                    && sr.sharedMaterial.shader.name == "IndianOcean/SpriteEchoOutline")
                    continue;

                // 读取自定义描边覆盖（颜色/宽度/禁用）
                var colorOverride = sr.GetComponentInParent<EchoOutlineColorOverride>();
                if (colorOverride != null && colorOverride.disableOutline) continue;

                CreateOutlineChild(sr, colorOverride);
            }

            _renderersEnabled = false;
            UpdateRendererEnabled();
        }

        private void CreateOutlineChild(SpriteRenderer parent, EchoOutlineColorOverride colorOverride)
        {
            var child = new GameObject($"EchoOutline_{parent.gameObject.name}");
            child.transform.SetParent(parent.transform, false);
            child.transform.localPosition = Vector3.zero;
            child.transform.localRotation = Quaternion.identity;
            child.transform.localScale = Vector3.one;

            var cr = child.AddComponent<SpriteRenderer>();
            cr.sprite = parent.sprite;
            cr.color = Color.white;
            cr.flipX = parent.flipX;
            cr.flipY = parent.flipY;
            // 有自定义颜色/宽度时创建材质实例；否则共享材质
            if (colorOverride != null)
            {
                // 用材质实例而非 MPB：MPB 会干扰 SpriteRenderer 的 _MainTex 自动绑定，
                // 导致 shader 采样到白色贴图 → alpha=1 → 描边公式算出 0 → 描边消失
                var mat = new Material(outlineMaterial);
                mat.SetColor(OutlineColorID, colorOverride.outlineColor);
                if (colorOverride.outlineWidth >= 0f)
                    mat.SetFloat(OutlineWidthID, colorOverride.outlineWidth);
                if (parent.sprite != null)
                    mat.SetTexture(MainTexID, parent.sprite.texture);
                cr.sharedMaterial = mat;
            }
            else
            {
                cr.sharedMaterial = outlineMaterial;
            }

            cr.sortingLayerID = parent.sortingLayerID;
            cr.sortingOrder = parent.sortingOrder + 1;
            cr.enabled = false; // 默认关闭，回声激活时再开

            _parentRenderers.Add(parent);
            _outlineRenderers.Add(cr);
        }

        private void Update()
        {
            // 回声不活跃时关闭所有描边渲染器（省 draw call）
            UpdateRendererEnabled();

            // 同步精灵帧（动画）、翻转、排序
            if (!_renderersEnabled) return;

            for (int i = 0; i < _outlineRenderers.Count; i++)
            {
                var cr = _outlineRenderers[i];
                var pr = _parentRenderers[i];
                if (pr == null || cr == null) continue;

                if (cr.sprite != pr.sprite)
                {
                    cr.sprite = pr.sprite;
                    // 有自定义材质实例时同步纹理（共享材质由 SpriteRenderer 自动绑定）
                    var mat = cr.sharedMaterial;
                    if (mat != null && mat != outlineMaterial && pr.sprite != null)
                        mat.SetTexture(MainTexID, pr.sprite.texture);
                }
                if (cr.flipX != pr.flipX) cr.flipX = pr.flipX;
                if (cr.flipY != pr.flipY) cr.flipY = pr.flipY;
                if (cr.sortingLayerID != pr.sortingLayerID) cr.sortingLayerID = pr.sortingLayerID;
                if (cr.sortingOrder != pr.sortingOrder + 1) cr.sortingOrder = pr.sortingOrder + 1;
            }
        }

        private void UpdateRendererEnabled()
        {
            float intensity = Shader.GetGlobalFloat(EchoIntensityID);
            bool shouldEnable = intensity > 0.01f;
            if (shouldEnable == _renderersEnabled) return;

            _renderersEnabled = shouldEnable;
            for (int i = 0; i < _outlineRenderers.Count; i++)
            {
                if (_outlineRenderers[i] != null)
                    _outlineRenderers[i].enabled = shouldEnable;
            }
        }

        private void ClearOutlines()
        {
            for (int i = 0; i < _outlineRenderers.Count; i++)
            {
                if (_outlineRenderers[i] != null)
                {
                    // 清理自定义材质实例（共享材质 outlineMaterial 不销毁）
                    var mat = _outlineRenderers[i].sharedMaterial;
                    if (mat != null && mat != outlineMaterial)
                        Destroy(mat);
                    Destroy(_outlineRenderers[i].gameObject);
                }
            }
            _parentRenderers.Clear();
            _outlineRenderers.Clear();
        }

        private void OnDestroy()
        {
            ClearOutlines();
        }
    }
}
