using agora_gaming_rtc;
using SC.XR.Unity;
using ShadowStudio.Model;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using UnityEngine.UI;
using XRTool.Util;
using static agora_gaming_rtc.ExternalVideoFrame;

public class AgoraRTCManager : SingletonMono<AgoraRTCManager> 
{

    [Header("_____________Basic Configuration_____________")]
    [FormerlySerializedAs("APP_ID")]
    [SerializeField]
    private string _appID = "";

    [FormerlySerializedAs("TOKEN")]
    [SerializeField]
    private string _token = "";

    [FormerlySerializedAs("CHANNEL_NAME")]
    [SerializeField]
    private string _channelName = "";

    private uint uid;
    private string peerid;
    internal IRtcEngine RtcEngine = null;

    private AgoraCustomPeer myPeer;
    private Dictionary<string, uint> dicPeeridAndUid;
    private List<AgoraCustomPeer> listCustomPeer;
    public bool isSwitchCamera;

    public uint Uid
    {
        get { return uid; }
        set {  uid = value; }
    }
    public AgoraCustomPeer MyPeer
    {
        get { return myPeer; }
        set { if(value!=null) myPeer = value; } 
    }
    public string ChannelName
    {
        get { return _channelName; }
        set { if (value != null) _channelName = value; }
    }
    public string PeerId
    {
        get { return peerid; }
        set { if (value != null) peerid = value; }
    }
    private void Start()
    {
        LoadAssetData();
        //if (_appID.Length > 10)
        //{
           
        //}
        InitEngine();
        dicPeeridAndUid = new Dictionary<string, uint>();
        isSwitchCamera = false;
        listCustomPeer = new List<AgoraCustomPeer>();
    }
    private void Update()
    {
    }
  
    //Show data in AgoraBasicProfile
    [ContextMenu("ShowAgoraBasicProfileData")]
    private void LoadAssetData()
    {
    }

    private void InitEngine()
    {

        RtcEngine = IRtcEngine.GetEngine(_token);

        RtcEngine.DisableVideo();


    }

    public void JoinChannel()
    {
        Debug.Log("  JoinChannel  " + _channelName);
        RtcEngine.EnableAudio();
        if(DeviceType.type!="LeiNiao")
        {

            RtcEngine.DisableVideo();
        }

        RtcEngine.SetChannelProfile(CHANNEL_PROFILE.CHANNEL_PROFILE_COMMUNICATION);
        RtcEngine.SetClientRole(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);

        RtcEngine.JoinChannel(_channelName, "", uid);


        RtcEngine.DisableVideo();
        RtcEngine.DisableVideoObserver();
        StartCoroutine(InitVideoAndAduio(1f));

        if (!RTCINIT)
        {
            RTCINIT = true;
            if (DeviceType.type != "LeiNiao")
            {
                //StartCoroutine(RenderTexturesScreenCapture());
            }
        }
    }
    static bool RTCINIT;
    Texture2D screenShot;
    IEnumerator RenderTexturesScreenCapture()
    {

        Debug.Log("RenderTexturesScreenCapture����ͼƬ1");
        yield return new WaitForEndOfFrame();
        if (screenShot == null)
        {
            screenShot = new Texture2D(1280, 720, TextureFormat.RGBA32, false);
            StartCoroutine(GetRenederFPS());
        }
        while (true)
        {
            // if (isSendVideo)
            //     continue;

            //    img.texture = RemoteRtc.Instance.cam.activeTexture;
            //  RenderTexture.active = ca.activeTexture;

            //  screenShot.ReadPixels(new Rect(0, 0, ca.activeTexture.width, ca.activeTexture.height), 0, 0);
            // screenShot.Apply();
            //Camera.main.targetTexture = null;
            //   RenderTexture.active = null;
            yield return new WaitForSeconds(0.05f);
            if (bts != null)
            {
                //  screenShot = HorizontalFlipTexture(screenShot2);
                var timetick = System.DateTime.Now.Ticks / 10000;
                ExternalVideoFrame externalVideoFrame = new ExternalVideoFrame();
                externalVideoFrame.type = VIDEO_BUFFER_TYPE.VIDEO_BUFFER_RAW_DATA;
                externalVideoFrame.format = VIDEO_PIXEL_FORMAT.VIDEO_PIXEL_RGBA;
                externalVideoFrame.buffer = bts;// screenShot.GetRawTextureData();
                externalVideoFrame.stride = (int)screenShot.width;
                externalVideoFrame.height = (int)screenShot.height;
                externalVideoFrame.rotation = 180;
                externalVideoFrame.cropLeft = 1;
                externalVideoFrame.cropRight = 1;
                externalVideoFrame.timestamp = timetick;
                RtcEngine.PushVideoFrame(externalVideoFrame);

               // Debug.Log("��������������");
            }
        }
    }
    public Camera cam2;
    byte[] bts;
    IEnumerator GetRenederFPS()
    {
        while (true)
        {
            var req = AsyncGPUReadback.Request(cam2.activeTexture);
            yield return new WaitUntil(() => req.done);
            if (!req.hasError)
            {

                if (bts == null)
                {
                    bts = new byte[req.layerDataSize];
                }
                req.GetData<byte>().CopyTo(bts);
                //   screenShot.LoadRawTextureData(bts);
                //  screenShot.Apply();
                //  tex.SetPixels32(req.GetData<Color32>().ToArray());
                //  img.texture = screenShot;
            }
            else
            {
                Debug.LogError("Error AsyncGPUReadbackRequest.hasError");
            }
        }
    }
    public void LeaveChannel()
    {
        Debug.Log("LeaveChannel ");
        int msg = RtcEngine.LeaveChannel();
        switch (msg)
        {
            case 0:
                Debug.Log( "成功退出频道: " + _channelName);
                break;
            default:
                Debug.Log("退出频道失败: " + msg);
                break;
        }
       
    }

    public void ClearDatas()
    {
        myPeer = null;
        dicPeeridAndUid.Clear();
        dicPeeridAndUid = new Dictionary<string, uint>();
        listCustomPeer.Clear();
        listCustomPeer = new List<AgoraCustomPeer>();
    }

    private IEnumerator InitVideoAndAduio(float times)
    {
        yield return new WaitForSeconds(times);

    //    MuteLocalVideoStream(CustomInfo.isSendVideo);
        MuteLocalAudioStream(CustomInfo.isSendAudio);
        MyPeer.isAudio = true;
   //     MyPeer.isVideo = true;

    }

    public void AddDicPeerData(string peerid, uint uid)
    {
        if (dicPeeridAndUid.ContainsKey(peerid))
            return;
        dicPeeridAndUid.Add(peerid, uid);
        AgoraCustomPeer peer = new AgoraCustomPeer();
        peer.AgoraInit(peerid);
        listCustomPeer.Add(peer);
        if (peerid == PeerId)
            MyPeer = peer;
    }

    public void RemDicPeerData(string peerid)
    {
        Debug.Log(" RemAtPeeridUid " + peerid + "   " + uid);
        dicPeeridAndUid.Remove(peerid);
        for (int i = 0; i < listCustomPeer.Count; i++)
        {
            if (listCustomPeer[i].peerId == peerid)
                listCustomPeer.Remove(listCustomPeer[i]);
        }
    }

    public void SetCustomPeerName(string peerid, string name)
    {
        Debug.Log("SetListCustomPeer  " + peerid + "   " + name);
        for (int i = 0; i < listCustomPeer.Count; i++)
        {
            if (peerid == listCustomPeer[i].peerId)
            {
                listCustomPeer[i].SetName(name);
                break;
            }

        }
    }

    public AgoraCustomPeer GetCustomPeer(string peerid)
    {
        Debug.Log("GetListCustomPeer  " + peerid);
        for (int i = 0; i < listCustomPeer.Count; i++)
        {
            if (listCustomPeer[i].peerId == peerid)
                return listCustomPeer[i];
        }
        return null;
    }

    public void AgoarRawImageVideoView(string peerId, RawImage rawImage)
    {

        Debug.Log(" AgoarRawImageVideoView " + peerId);
        try
        {
            if (peerId == CommonMethod.MyPeer.PeerId)
            {
                rawImage.gameObject.SetActive(true);
                rawImage.rectTransform.localEulerAngles = new Vector3(0, 180, 180);
                MakeVideoView(0, rawImage);
            }
            else if (dicPeeridAndUid.ContainsKey(peerId))
            {
                //  list_ShowView.Add(peerId, rawImage);
                rawImage.gameObject.SetActive(true);
                rawImage.rectTransform.localEulerAngles = new Vector3(0, 0, 180);

                MakeVideoView(dicPeeridAndUid[peerId], rawImage, this._channelName);
            }


        }
        catch (System.Exception e)
        {

            HttpsSendLog.Instance.SendLog("Agora", e.ToString());
        }
      

    }

    public void MuteLocalAudioStream(bool isAudio)
    {
        int msg = RtcEngine.MuteLocalAudioStream(!isAudio);

        //  int msg = RtcEngine.EnableLocalAudio(isAudio);
        switch (msg)
        {
            case 0:
                Debug.Log(isAudio ? "打开本地音频成功" : "关闭本地音频成功 ");
                MyPeer.isOpenAduio = !isAudio;
                break;
            default:
                Debug.LogError("开关本地音频失败: " + msg);
                break;
        }
    }

    public void MuteRemoteAudioStream(string peerid, bool isAudio)
    {
        Debug.Log(peerid);
        if (!dicPeeridAndUid.ContainsKey(peerid))
            return;
        int msg = RtcEngine.MuteRemoteAudioStream(dicPeeridAndUid[peerid], !isAudio);

        switch (msg)
        {
            case 0:
                Debug.Log(isAudio ? "订阅远端音频成功" : "取订远端音频成功 ");
                break;
            default:
                Debug.LogError("开关本地音频失败: " + msg);
                break;
        }
    }

    public void MuteLocalVideoStream(bool isVideo)
    {
        return;
        if(isVideo)
        {
            XRRGBCamera.Instance.playCamera(CustomInfo.mWidth, CustomInfo.mHight);

        }
        else
        {

            XRRGBCamera.Instance.stopCamera();
        }
        int msg = RtcEngine.MuteLocalVideoStream(!isVideo);
        //RtcEngine.EnableVideo();
        //int msg = RtcEngine.EnableLocalVideo(isVideo);

        switch (msg)
        {
            case 0:
                Debug.Log(isVideo ? "打开本地视频成功 " : "关闭本地视频成功 ");
                //  myPeer.isCloseVideo = !isVideo;
                MyPeer.isOpenVideo = !isVideo;
                break;
            default:
                Debug.LogError("开关本地视频失败: " + msg);
                break;
        }

    }


    public void MuteRemoteVideoStream(string peerid, bool isVideo)
    {
        //  Debug.Log(peerid);
        if (!dicPeeridAndUid.ContainsKey(peerid))
            return;
        int msg = RtcEngine.MuteRemoteVideoStream(dicPeeridAndUid[peerid], !isVideo);

        switch (msg)
        {
            case 0:
                Debug.Log(isVideo ? "订阅远端视频成功" : "取订远端视频成功 ");
                break;
            default:
                Debug.LogError("开关本地音频失败: " + msg);
                break;
        }
    }

    public void RemoteVideoStateChanged(uint uid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON
   reason)
    {
        Debug.Log(uid + "       " + state + "      " + reason);
        Debug.Log("RemoteVideoStateChanged   " + uid);
        if (!dicPeeridAndUid.ContainsValue(uid))
            return;
        for (int i = 0; i < listCustomPeer.Count; i++)
        {
            if (dicPeeridAndUid[listCustomPeer[i].peerId] == uid)
            {
                switch (state)
                {
                    case REMOTE_VIDEO_STATE.REMOTE_VIDEO_STATE_STOPPED:
                        // listCustomPeer[i].isVideo = false;
                        break;
                    case REMOTE_VIDEO_STATE.REMOTE_VIDEO_STATE_STARTING:
                        listCustomPeer[i].isVideo = true;
                        break;
                    case REMOTE_VIDEO_STATE.REMOTE_VIDEO_STATE_DECODING:
                        listCustomPeer[i].isOpenVideo = false;
                        break;
                    case REMOTE_VIDEO_STATE.REMOTE_VIDEO_STATE_FROZEN:
                        break;
                    case REMOTE_VIDEO_STATE.REMOTE_VIDEO_STATE_FAILED:
                        //  listCustomPeer[i].isVideo = false;
                        break;
                    default:
                        break;
                }
                switch (reason)
                {
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_INTERNAL:
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_NETWORK_CONGESTION://网络阻塞�?

                        //  listCustomPeer[i].isVideo = false;
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_NETWORK_RECOVERY:// 网络恢复正常�?

                        //  listCustomPeer[i].isVideo = true;
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_LOCAL_MUTED://本地用户停止接收远端视频流或本地用户禁用视频模块

                        listCustomPeer[i].isOpenVideo = true;
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_LOCAL_UNMUTED://本地用户恢复接收远端视频流或本地用户启动视频模块

                        listCustomPeer[i].isOpenVideo = false;
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_REMOTE_MUTED://远端用户停止发送视频流或远端用户禁用视频模块�?

                        listCustomPeer[i].isVideo = false;
                        //  CloseAgoraMainImage(listCustomPeer[i].peerId, false);
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_REMOTE_UNMUTED://远端用户恢复发送视频流或远端用户启用视频模块�?

                        listCustomPeer[i].isVideo = true;
                        //  CloseAgoraMainImage(listCustomPeer[i].peerId, true);
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_REMOTE_OFFLINE: //远端用户离开频道�?

                        listCustomPeer[i].isVideo = false;
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_AUDIO_FALLBACK:
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_AUDIO_FALLBACK_RECOVERY:
                        break;
                    default:
                        break;
                }
                break;
            }
        }

    }

    public void RemoteAudioStateChanged(uint uid, REMOTE_AUDIO_STATE state, REMOTE_AUDIO_STATE_REASON reason)
    {
        Debug.Log(uid + "       " + state + "      " + reason);
        //   Debug.Log("RemoteAudioStateChanged   " + uid);
        if (!dicPeeridAndUid.ContainsValue(uid))
            return;
        //  Debug.Log("RemoteAudioStateChanged   " + 1);
        for (int i = 0; i < listCustomPeer.Count; i++)
        {
            Debug.Log(listCustomPeer[i].peerId);
            if (dicPeeridAndUid[listCustomPeer[i].peerId] == uid)
            {
                //  Debug.Log("RemoteAudioStateChanged   " + 2);
                switch (state)
                {
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_STOPPED:
                        //    listCustomPeer[i].isAudio = false;
                        break;
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_STARTING:
                        listCustomPeer[i].isAudio = true;
                        break;
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_DECODING:
                        listCustomPeer[i].isOpenAduio = false;
                        break;
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_FROZEN:
                        break;
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_FAILED:
                        // listCustomPeer[i].isAudio = false;
                        break;
                    default:
                        break;
                }
                switch (reason)
                {
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_INTERNAL:
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_NETWORK_CONGESTION:
                        //  listCustomPeer[i].isAudio = false;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_NETWORK_RECOVERY:
                        //  listCustomPeer[i].isAudio = true;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_LOCAL_MUTED:
                        listCustomPeer[i].isOpenAduio = true;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_LOCAL_UNMUTED:
                        listCustomPeer[i].isOpenAduio = false;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_REMOTE_MUTED:
                        listCustomPeer[i].isAudio = false;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_REMOTE_UNMUTED:
                        listCustomPeer[i].isAudio = true;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_REMOTE_OFFLINE:
                        listCustomPeer[i].isAudio = false;
                        break;
                    default:
                        break;
                }
                break;
            }
        }
    }

    private void OnDestroy()
    {
        Debug.Log("OnDestroy");
        if (RtcEngine == null) return;
        RtcEngine.LeaveChannel();
    }
    internal static void MakeVideoView(uint uid, RawImage rawImage, string channelId = "")
    {
        Debug.Log("MakeVideoView   " + uid);
        //var go = GameObject.Find(uid.ToString());
        //if (!ReferenceEquals(go, null))
        //{
        //    return; // reuse
        //}

        // create a GameObject and assign to this new user
        // var videoSurface = MakePlaneSurface(uid.ToString());
        // configure videoSurface
        if (uid == 0)
        {
            rawImage.transform.localEulerAngles = Vector3.zero;
            //videoSurface.SetForUser(uid, channelId);
            rawImage.texture = AgoraRTCManager.Instance.cam2.activeTexture;
        }
        else
        {
            rawImage.transform.localEulerAngles = new Vector3(-180,180,0);
            var videoSurface = MakeImageSurface(rawImage);

            if (ReferenceEquals(videoSurface, null)) return;

            videoSurface.SetForUser(uid);
            videoSurface.SetEnable(true);
        }

        //videoSurface.OnTextureSizeModify += (int width, int height) =>
        //{
        //    float scale = (float)height / (float)width;
        //    videoSurface.transform.localScale = new Vector3(-5, 5 * scale, 1);
        //    Debug.Log("OnTextureSizeModify: " + width + "  " + height);
        //};

    }
    internal static void OnUserJoined(uint uid)
    {
        // _videoSample.Log.UpdateLog(string.Format("OnUserJoined uid: ${0} elapsed: ${1}", uid, elapsed));
        // Debug.Log(string.Format("OnUserJoined uid: ${0} elapsed: ${1}", uid, elapsed))

        AgoraRTCManager.Instance.RtcEngine.GetUserInfoByUid(uid);

    }
    internal static void OnRemoteVideoStateChanged(uint uid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON
       reason)
    {
        AgoraRTCManager.Instance.RemoteVideoStateChanged(uid, state, reason);
    }
    internal static void OnRemoteAudioStateChanged(uint uid, REMOTE_AUDIO_STATE state, REMOTE_AUDIO_STATE_REASON reason)
    {
        AgoraRTCManager.Instance.RemoteAudioStateChanged(uid, state, reason);
    }
    #region -- Video Render UI Logic ---

    // VIDEO TYPE 1: 3D Object
    private static VideoSurface MakePlaneSurface(string goName)
    {
        var go = GameObject.CreatePrimitive(PrimitiveType.Quad);

        //for (int i = 0; i < list_UserInfo.Count; i++)
        //{
        //    if (list_UserInfo[i].uid.ToString() == goName)
        //    {
        //        string userAccount = list_UserInfo[i].userAccount;
        //        if (AgoraVideoAudioManager.Instance.list_ShowView.ContainsKey(list_UserInfo[i].userAccount))
        //        {
        //            go = AgoraVideoAudioManager.Instance.list_ShowView[list_UserInfo[i].userAccount].gameObject;
        //        }
        //        else
        //            Debug.LogError("  Agora ShowView is NULL ");
        //    }
        //}

        if (go == null)
        {
            go = GameObject.CreatePrimitive(PrimitiveType.Plane);
            return null;
        }

        go.name = goName;
        // set up transform
        go.transform.Rotate(-90.0f, 0.0f, 0.0f);
        var yPos = Random.Range(3.0f, 5.0f);
        var xPos = Random.Range(-2.0f, 2.0f);
        go.transform.position = Vector3.zero;
        go.transform.localScale = new Vector3(0.25f, 0.5f, 0.5f);

        // configure videoSurface
        var videoSurface = go.AddComponent<VideoSurface>();
        return videoSurface;
    }

    // Video TYPE 2: RawImage
    private static VideoSurface MakeImageSurface(RawImage rawImage)
    {
        var videoSurface = rawImage.gameObject.AddComponent<VideoSurface>();
        return videoSurface;
    }



    #endregion
}