using System;
using UnityEngine.Rendering.RenderGraphModule;

// cleanup code
// listMinDepth and maxDepth should be stored in a different uniform block?
// Point lights stored as vec4
// RelLightIndices should be stored in ushort instead of uint.
// TODO use Unity.Mathematics
// TODO Check if there is a bitarray structure (with dynamic size) available in Unity

namespace UnityEngine.Rendering.Universal.Internal
{
    // Render all tiled-based deferred lights.
    internal class DeferredPass : ScriptableRenderPass
    {
        DeferredLights m_DeferredLights;

        public DeferredPass(RenderPassEvent evt, DeferredLights deferredLights)
        {
            profilingSampler = new ProfilingSampler("Render Deferred Lighting");
            base.renderPassEvent = evt;
            m_DeferredLights = deferredLights;
        }

        private class PassData
        {
            internal UniversalCameraData cameraData;
            internal UniversalLightData lightData;
            internal UniversalShadowData shadowData;

            internal TextureHandle[] gbuffer;
            internal DeferredLights deferredLights;
        }

        internal void Render(RenderGraph renderGraph, ContextContainer frameData, TextureHandle color, TextureHandle depth, TextureHandle[] gbuffer)
        {
            UniversalCameraData cameraData = frameData.Get<UniversalCameraData>();
            UniversalLightData lightData = frameData.Get<UniversalLightData>();
            UniversalShadowData shadowData = frameData.Get<UniversalShadowData>();

            using (var builder = renderGraph.AddRasterRenderPass<PassData>(passName, out var passData, profilingSampler))
            {
                passData.cameraData = cameraData;
                passData.lightData = lightData;
                passData.shadowData = shadowData;

                builder.SetRenderAttachment(color, 0, AccessFlags.Write);
                builder.SetRenderAttachmentDepth(depth, AccessFlags.ReadWrite);
                passData.deferredLights = m_DeferredLights;

                if (!m_DeferredLights.UseFramebufferFetch)
                {
                    for (int i = 0; i < gbuffer.Length; ++i)
                    {
                        if (i != m_DeferredLights.GBufferLightingIndex)
                            builder.UseTexture(gbuffer[i], AccessFlags.Read);
                    }
                }
                else
                {
                    var idx = 0;
                    for (int i = 0; i < gbuffer.Length; ++i)
                    {
                        if (i != m_DeferredLights.GBufferLightingIndex)
                        {
                            builder.SetInputAttachment(gbuffer[i], idx);
                            idx++;
                        }
                    }
                }

                builder.AllowGlobalStateModification(true);

                builder.SetRenderFunc(static (PassData data, RasterGraphContext context) =>
                {
                    data.deferredLights.ExecuteDeferredPass(context.cmd, data.cameraData, data.lightData, data.shadowData);
                });
            }
        }

        // ScriptableRenderPass
        public override void OnCameraCleanup(CommandBuffer cmd)
        {
            m_DeferredLights.OnCameraCleanup(cmd);
        }
    }
}