using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.Rendering.RenderGraphModule;
using UnityEngine.Rendering.RenderGraphModule.Util;

public class UIBlurDualKawaseFeature : ScriptableRendererFeature
{
    [System.Serializable]
    public class Settings
    {
        public RenderPassEvent passEvent = RenderPassEvent.AfterRenderingTransparents;

        [Range(0.25f, 1f)] public float downscale = 0.5f; // 0.5(中高端) / 0.25(低端更稳)
        [Range(1, 6)] public int blurPasses = 4;          // 3~4 移动端常用
        [Range(0.5f, 4f)] public float offset = 1.0f;     // 糊的“扩散感”

        public bool updateEveryFrame = false;             // 推荐 false，只在需要时刷新
        public string refreshFlagName = "_UIBlurRefresh"; // UI 触发用
        public string globalTextureName = "_UIBlurTexture";

        public Shader blurShader;                         // Hidden/URP/DualKawaseBlur
    }

    public Settings settings = new Settings();

    class Pass : ScriptableRenderPass
    {
        readonly Settings s;
        readonly Material mat;

        // 持久 RT：让 UI 能跨帧拿到（需要 ImportTexture）:contentReference[oaicite:2]{index=2}
        RTHandle persistentOutput;

        static readonly int SourceTexId = Shader.PropertyToID("_SourceTex");
        static readonly int OffsetId = Shader.PropertyToID("_Offset");

        public Pass(Settings settings, Material material)
        {
            s = settings;
            mat = material;
        }

        public RTHandle OutputRT => persistentOutput;

        public void EnsureOutput(ref RenderTextureDescriptor desc, int w, int h)
        {
            desc.width = w;
            desc.height = h;
            desc.depthBufferBits = 0;
            desc.msaaSamples = 1;
            desc.useMipMap = false;
            desc.autoGenerateMips = false;

            RenderingUtils.ReAllocateIfNeeded(
                ref persistentOutput,
                desc,
                FilterMode.Bilinear,
                TextureWrapMode.Clamp,
                name: s.globalTextureName
            );
        }

        public override void RecordRenderGraph(RenderGraph renderGraph, ContextContainer frameData)
        {
            // 资源/相机数据（官方示例也是这么取 activeColorTexture）:contentReference[oaicite:3]{index=3}
            var resourceData = frameData.Get<UniversalResourceData>();
            var cameraData = frameData.Get<UniversalCameraData>();

            // 避免从 backbuffer blit（官方示例也这么做）:contentReference[oaicite:4]{index=4}
            if (resourceData.isActiveTargetBackBuffer)
                return;

            // 刷新策略：不每帧更新时，只有收到 UI 请求才做一轮
            if (!s.updateEveryFrame)
            {
                if (Shader.GetGlobalInt(s.refreshFlagName) == 0)
                    return;

                Shader.SetGlobalInt(s.refreshFlagName, 0);
            }

            // 基础描述符（跟相机一致）
            var desc = cameraData.cameraTargetDescriptor;
            desc.depthBufferBits = 0;
            desc.msaaSamples = 1;

            int baseW = Mathf.Max(16, Mathf.RoundToInt(desc.width * s.downscale));
            int baseH = Mathf.Max(16, Mathf.RoundToInt(desc.height * s.downscale));

            EnsureOutput(ref desc, baseW, baseH);

            // 把持久 RTHandle 导入 RenderGraph（跨帧可用）:contentReference[oaicite:5]{index=5}
            TextureHandle outTex = renderGraph.ImportTexture(persistentOutput);

            // 生成金字塔：0层(base), 1层(/2), 2层(/4)...
            int n = Mathf.Clamp(s.blurPasses, 1, 8);
            TextureHandle[] pyr = new TextureHandle[n];

            for (int i = 0; i < n; i++)
            {
                int w = Mathf.Max(8, baseW >> i);
                int h = Mathf.Max(8, baseH >> i);

                var d = desc;
                d.width = w;
                d.height = h;
                pyr[i] = UniversalRenderer.CreateRenderGraphTexture(renderGraph, d, $"_UIBlurPyr{i}", false);
            }

            mat.SetFloat(OffsetId, s.offset);

            // source：相机颜色
            TextureHandle src = resourceData.activeColorTexture;

            // Downsample chain (pass 0)
            {
                var p = new RenderGraphUtils.BlitMaterialParameters(src, pyr[0], mat, 0);
                renderGraph.AddBlitPass(p, "UIBlur DualKawase Down 0");
            }
            for (int i = 1; i < n; i++)
            {
                var p = new RenderGraphUtils.BlitMaterialParameters(pyr[i - 1], pyr[i], mat, 0);
                renderGraph.AddBlitPass(p, $"UIBlur DualKawase Down {i}");
            }

            // Upsample chain (pass 1)
            for (int i = n - 1; i > 0; i--)
            {
                var p = new RenderGraphUtils.BlitMaterialParameters(pyr[i], pyr[i - 1], mat, 1);
                renderGraph.AddBlitPass(p, $"UIBlur DualKawase Up {i}");
            }

            // 最终写到持久输出 RT
            {
                var p = new RenderGraphUtils.BlitMaterialParameters(pyr[0], outTex, mat, 1);
                renderGraph.AddBlitPass(p, "UIBlur DualKawase Final");
            }
        }

        public void Cleanup()
        {
            persistentOutput?.Release();
            persistentOutput = null;
        }
    }

    Material _mat;
    Pass _pass;

    public override void Create()
    {
        if (settings.blurShader == null)
            settings.blurShader = Shader.Find("Hidden/URP/DualKawaseBlur");

        if (settings.blurShader != null)
            _mat = CoreUtils.CreateEngineMaterial(settings.blurShader);

        _pass = new Pass(settings, _mat) { renderPassEvent = settings.passEvent };
    }

    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        if (_mat == null) return;
        if (renderingData.cameraData.cameraType != CameraType.Game) return;

        // 这里提前把全局纹理指向持久 RT（即使本帧不刷新，也能用旧结果）
        if (_pass.OutputRT != null)
            Shader.SetGlobalTexture(settings.globalTextureName, _pass.OutputRT);

        renderer.EnqueuePass(_pass);
    }

    protected override void Dispose(bool disposing)
    {
        _pass?.Cleanup();
        CoreUtils.Destroy(_mat);
    }
}
