using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Unity.VisualScripting;
using UnityEditor;
using UnityEditor.Recorder;
using UnityEditor.Recorder.Input;
using UnityEngine;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.UI;
using UnityEngine.Windows.WebCam;

[ExecuteInEditMode]
public class ShaderManiuplation : MonoBehaviour
{
    public enum EquilateralDirection
    {
        Forward,
        Left,
        Backwards,
        Right
    }

    public enum ProjectionType
    {
        Squeeze,
        Gnomic
    }

    List<Shader> m_ShaderList = new List<Shader>();

    Material mat;
    public EquilateralDirection m_Direction = EquilateralDirection.Backwards;
    public ProjectionType m_ProjectionType = ProjectionType.Gnomic;
    GameObject m_CubeMapPrefab = null;


    public float m_GnomicCameraHeight;
    public float m_SqueezedCameraHeight;

    // Game View Parameters
    Type gameView;
    PropertyInfo selectedSizeIndex;
    EditorWindow window;


    private void OnEnable()
    {
        SetupEditorSettings();
        SetupMatShaders();
    }

    void UpdateProjectionType()
    {
        if(m_ShaderList != null && m_ShaderList.Count > 0)
        {
            if (m_ProjectionType == ProjectionType.Squeeze)
            {

                SetShaderSqueezed(21, 0.85f, 2.5f, 3.5f, 4f, m_SqueezedCameraHeight);
            }
            else if (m_ProjectionType == ProjectionType.Gnomic)
            {
                SetShaderGnomic(28, 1.5f, 0.2f, 5.13f, 0.125f, m_GnomicCameraHeight);
            }
        }
    }

    private void SetShaderSqueezed(int resolutionPreset, float yRotation, float xRotation, float yDivide, float xDivide, float cameraHeight)
    {
        mat.shader = m_ShaderList[0];
        mat.SetFloat("_EquiRotation", xRotation + SetDirection());
        mat.SetFloat("_EquiRotationY", yRotation);
        mat.SetFloat("_DivideY", yDivide);
        mat.SetFloat("_DivideX", xDivide);
        ChangeGameViewResolution(resolutionPreset);
        m_CubeMapPrefab.transform.localPosition = new Vector3(m_CubeMapPrefab.transform.localPosition.x, cameraHeight, m_CubeMapPrefab.transform.localPosition.z);
        
    }

    private void SetShaderGnomic(int resolutionPreset, float xFOV, float yFOV, float yRotation, float xRotation, float cameraHeight)
    {
        mat.shader = m_ShaderList[1];

        if (m_Direction == EquilateralDirection.Left || m_Direction == EquilateralDirection.Right)
        {
            ChangeGameViewResolution(29);
            xFOV = 0.9f;
            yFOV = 0.3f;
            yRotation = 5.23f;
        }
        else
        {
            ChangeGameViewResolution(resolutionPreset);
        }

        mat.SetFloat("_EquiRotation", xRotation + SetDirection());
        mat.SetFloat("_EquiRotationY", yRotation);
        mat.SetFloat("_FOVScale_X", xFOV);
        mat.SetFloat("_FOVScale_Y", yFOV);

        m_CubeMapPrefab.transform.localPosition = new Vector3(m_CubeMapPrefab.transform.localPosition.x, cameraHeight, m_CubeMapPrefab.transform.localPosition.z);

    }

    private float SetDirection()
    {
        float directionOffset = 0f;

        if (m_ProjectionType == ProjectionType.Gnomic)
        {
            switch(m_Direction)
            {
                case EquilateralDirection.Left:
                    directionOffset = 0.25f;
                    break;
                case EquilateralDirection.Right:
                    directionOffset = 0.75f;
                    break;
                case EquilateralDirection.Forward:
                    directionOffset = 0;
                    break;
                case EquilateralDirection.Backwards:
                    directionOffset = 0.5f;
                    break;
            }
        }

        if (m_ProjectionType == ProjectionType.Squeeze)
        {
            switch (m_Direction)
            {
                case EquilateralDirection.Left:
                    directionOffset = 1;
                    break;
                case EquilateralDirection.Right:
                    directionOffset = 3;
                    break;
                case EquilateralDirection.Forward:
                    directionOffset = 0;
                    break;
                case EquilateralDirection.Backwards:
                    directionOffset = 2;
                    break;
            }
        }

        return directionOffset;
    }

    private void OnValidate()
    {
        UpdateProjectionType();
    }

    void ChangeGameViewResolution(int index)
    {
        Debug.Log($"{index}");
        selectedSizeIndex.SetValue(window, index, null);
    }

    private void SetupEditorSettings()
    {
        gameView = typeof(Editor).Assembly.GetType("UnityEditor.GameView");
        selectedSizeIndex = gameView.GetProperty("selectedSizeIndex", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        window = EditorWindow.GetWindow(gameView);
    }

    private void SetupMatShaders()
    {
        mat = this.GetComponent<RawImage>().material;
        m_ShaderList.Add(Shader.Find("Conversion/CubemapToEquirectangularSqueeze"));
        m_ShaderList.Add(Shader.Find("Conversion/CubemapToEquirectangularGnomic"));
        mat.shader = m_ShaderList[1];
        m_CubeMapPrefab = GameObject.Find("360 Projection Center");
    }

}