using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.UI;

internal class UIBackgroundPass : ScriptableRenderPass
{
    const string profilerTag = "UIBackgroundPass";
    RenderTargetIdentifier source;
    RenderTextureDescriptor desc;

    ProfilingSampler m_ProfilingSampler;

    public UIBackgroundPass(RenderPassEvent evt)
    {
        renderPassEvent = evt;

        m_ShaderTagIdList.Add(new ShaderTagId("UniversalPipelineUI"));
        m_ShaderTagIdList.Add(new ShaderTagId("UniversalForward"));
        m_ShaderTagIdList.Add(new ShaderTagId("LightweightForward"));
        m_ShaderTagIdList.Add(new ShaderTagId("SRPDefaultUnlit"));
        m_ShaderTagIdList.Add(new ShaderTagId("ShaderTag3"));

        m_ProfilingSampler = new ProfilingSampler(profilerTag);
        material = new Material(Shader.Find("URP/UI/Default"));
    }

    public void Setup(RenderTextureDescriptor baseDescriptor, RenderTargetIdentifier source)
    {
        this.source = source;
        desc = baseDescriptor;
    }

    List<ShaderTagId> m_ShaderTagIdList = new List<ShaderTagId>();
    Material material;

    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        //if (renderingData.cameraData.isSceneViewCamera)
        //    return;

        if (material == null)
            return;

        CommandBuffer cmd = CommandBufferPool.Get(profilerTag);
        using (new ProfilingScope(cmd, m_ProfilingSampler))
        {
            var camera = renderingData.cameraData.camera;
            //var udata = camera.GetUniversalAdditionalCameraData();
            //var stack = udata.cameraStack;

            //foreach (var c in stack)
            //{
            //    if (!c.gameObject.CompareTag("UICamera"))
            //        c.enabled = false;
            //}
            //var go = GameObject.Find("bg-jsj-beijingd2").GetComponent<CanvasRenderer>();
            //lastCull = camera.cullingMask;
            //camera.cullingMask = 1 << LayerMask.NameToLayer("BackGround");

            //var sortFlags = renderingData.cameraData.defaultOpaqueSortFlags;
            //var drawSettings = CreateDrawingSettings(m_ShaderTagIdList, ref renderingData, SortingCriteria.CommonTransparent);
            //var filteringSettings = new FilteringSettings(RenderQueueRange.all, -1);

            //context.DrawRenderers(renderingData.cullResults, ref drawSettings, ref filteringSettings);

            var backgroundList = UIBackground.uiBackgroundQueue;
            foreach (var back in backgroundList)
            {
                if (back.MainCamera == null)
                    continue;
                if (back.UICanvas == null || !back.UICanvas.isRootCanvas || back.UICanvas.worldCamera == null)
                    continue;

                var image = back.BackgroundImage;

                if (back.DirtyMesh)
                {
                    back.DirtyMesh = false;

                    if (back.mesh == null)
                        back.mesh = new Mesh();
                    if (back.vertexHelp == null)
                        back.vertexHelp = new VertexHelper();

                    back.mesh.Clear();
                    back.vertexHelp.Clear();

                    GenerateSimpleSprite(back.vertexHelp, image);

                    back.vertexHelp.FillMesh(back.mesh);
                }

                material.SetTexture("_MainTex", image.mainTexture);

                //处理projectionMatrix的z-flip问题
                var uiCamera = back.UICanvas.worldCamera;
                var uiCameraMat = uiCamera.projectionMatrix;
                uiCameraMat.m02 *= -1;
                uiCameraMat.m12 *= -1;
                uiCameraMat.m22 *= -1;
                uiCameraMat.m32 *= -1;

                var mainCameraMat = back.MainCamera.projectionMatrix;
                mainCameraMat.m02 *= -1;
                mainCameraMat.m12 *= -1;
                mainCameraMat.m22 *= -1;
                mainCameraMat.m32 *= -1;
                mainCameraMat = mainCameraMat.inverse;

                //渲染到近裁面往后
                var zAxisMat = Matrix4x4.identity;
                zAxisMat.m22 = 0;
                zAxisMat.m23 = -0.95f;

                //保证两个摄像机渲染到同一个屏幕点
                var matrix = GetLocalToWorldMatrix(back.MainCamera.transform) * mainCameraMat * zAxisMat * uiCameraMat * GetWorldToLocalMatrix(uiCamera.transform) * image.transform.localToWorldMatrix;

                cmd.DrawMesh(back.mesh, matrix, material);
            }

            context.ExecuteCommandBuffer(cmd);
            CommandBufferPool.Release(cmd);
        }
    }

    public override void FrameCleanup(CommandBuffer cmd)
    {
        //camera.cullingMask = lastCull;
    }

    void GenerateSimpleSprite(VertexHelper vh, Image image)
    {
        Vector4 v = GetDrawingDimensions(image);
        var uv = (image.sprite != null) ? UnityEngine.Sprites.DataUtility.GetOuterUV(image.sprite) : Vector4.zero;

        var color32 = image.color;
        vh.Clear();
        vh.AddVert(new Vector3(v.x, v.y), color32, new Vector2(uv.x, uv.y));
        vh.AddVert(new Vector3(v.x, v.w), color32, new Vector2(uv.x, uv.w));
        vh.AddVert(new Vector3(v.z, v.w), color32, new Vector2(uv.z, uv.w));
        vh.AddVert(new Vector3(v.z, v.y), color32, new Vector2(uv.z, uv.y));

        vh.AddTriangle(0, 1, 2);
        vh.AddTriangle(2, 3, 0);
    }

    private Vector4 GetDrawingDimensions(Image image)
    {
        var activeSprite = image.sprite;
        var padding = activeSprite == null ? Vector4.zero : UnityEngine.Sprites.DataUtility.GetPadding(activeSprite);
        var size = activeSprite == null ? Vector2.zero : new Vector2(activeSprite.rect.width, activeSprite.rect.height);

        Rect r = image.GetPixelAdjustedRect();
        // Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r));

        int spriteW = Mathf.RoundToInt(size.x);
        int spriteH = Mathf.RoundToInt(size.y);

        var v = new Vector4(
            padding.x / spriteW,
            padding.y / spriteH,
            (spriteW - padding.z) / spriteW,
            (spriteH - padding.w) / spriteH);

        if (image.preserveAspect && size.sqrMagnitude > 0.0f)
        {
            PreserveSpriteAspectRatio(ref r, size, image.rectTransform);
        }

        v = new Vector4(
            r.x + r.width * v.x,
            r.y + r.height * v.y,
            r.x + r.width * v.z,
            r.y + r.height * v.w
        );

        return v;
    }

    private void PreserveSpriteAspectRatio(ref Rect rect, Vector2 spriteSize, RectTransform rectTransform)
    {
        var spriteRatio = spriteSize.x / spriteSize.y;
        var rectRatio = rect.width / rect.height;

        if (spriteRatio > rectRatio)
        {
            var oldHeight = rect.height;
            rect.height = rect.width * (1.0f / spriteRatio);
            rect.y += (oldHeight - rect.height) * rectTransform.pivot.y;
        }
        else
        {
            var oldWidth = rect.width;
            rect.width = rect.height * spriteRatio;
            rect.x += (oldWidth - rect.width) * rectTransform.pivot.x;
        }
    }

    public Matrix4x4 GetLocalToWorldMatrix(Transform transform)
    {
        return Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
    }

    public Matrix4x4 GetWorldToLocalMatrix(Transform transform)
    {
        return GetLocalToWorldMatrix(transform).inverse;
    }
}