using Agora.Rtc;
using Agora.Util;
using SC.XR.Unity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Serialization;
using UnityEngine.UI;
using XRTool.Util;
using Logger = Agora.Util.Logger;

public class AgoraVideoAudioManager : SingletonMono<AgoraVideoAudioManager>
{
    [FormerlySerializedAs("appIdInput")]
    [SerializeField]
    private AppIdInput _appIdInput;

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

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

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

    internal IRtcEngine RtcEngine = null;

    internal Logger Log;

    private bool isAudio;
    private bool isVideo;

    //private static List<Agora.Rtc.UserInfo> list_UserInfo;
    private Dictionary<string, uint> dicPeeridAndUid;
    public Text LogText;

    private bool isRoom;
    private CustomPeer myPeer;
    public uint uid;
    public string userAccount;
    //  private Dictionary<string, RawImage> list_ShowView;

    // public MenuIcon menuIcon;

    public bool isSwitchCamera;
    // Use this for initialization

    private string mainViewPeerId;

    private bool isSendVideo;
    public List<CustomPeer> listCustomPeer;
    private void Start()
    {
        LoadAssetData();
        if (CheckAppId())
        {
            InitEngine();
            //SetChinnelName("0003003");
            //JoinChannel();
            //SetupUI();
        }
        //list_UserInfo = new List<Agora.Rtc.UserInfo>();
        //    list_ShowView = new Dictionary<string, RawImage>();
        dicPeeridAndUid = new Dictionary<string, uint>();
        isRoom = false;
        isSwitchCamera = false;
        listCustomPeer = new List<CustomPeer>();

        //RTCManager.Instance.OnJoinChannel += JoinChannel;
        //RTCManager.Instance.OnLeaveChannel += LeaveChannel;
        //RTCManager.Instance.OnShowViewRawImage += AddListShowView;
        //RTCManager.Instance.OnMuteLocalAudioStream += EnableLoacalAudio;
        //RTCManager.Instance.OnMuteLocalVideoStream += EnableLocalVideo;
        //RTCManager.Instance.OnMuteRemoteAudioStream += MuteRemoteAudioStream;
        //RTCManager.Instance.OnMuteRemoteVideoStream += MuteRemoteVideoStream;
        //RTCManager.Instance.OnSetUid += SetUid;
        //RTCManager.Instance.OnSetChannelName += SetChinnelName;
        //RTCManager.Instance.OnAddPeeridUid += AddPeeridUid;
        //RTCManager.Instance.OnRemAtPeeridUid += RemAtPeeridUid;
    }

    // Update is called once per frame
    private void Update()
    {

        //if(isRoom&&CommonMethod.MyPeer!=null&&list_ShowView.Count>0)
        //{
        //    if(myPeer==null)
        //    {
        //        myPeer = (CustomPeer)StudioRtc.Instance.customPeerList.getPeerName(CommonMethod.MyPeer.PeerId);
        //        Debug.Log(" Get  MyCustomPeer");
        //    }

        //    if (myPeer == null) return;

        //    if (isAudio != myPeer.isAudio)
        //    {
        //        isAudio = myPeer.isAudio;
        //        EnableLoacalAudio(isAudio);
        //    }

        //    if(isVideo!= myPeer.isVideo)
        //    {
        //        isVideo = myPeer.isVideo;
        //        EnableLocalVideo(isVideo);
        //    }
        //}

    }

    //Show data in AgoraBasicProfile
    [ContextMenu("ShowAgoraBasicProfileData")]
    private void LoadAssetData()
    {
        if (_appIdInput == null) return;
        _appID = _appIdInput.appID;
        _token = _appIdInput.token;
        _channelName = _appIdInput.channelName;
    }


    private bool CheckAppId()
    {
        Log = new Logger(LogText);
        return Log.DebugAssert(_appID.Length > 10, "Please fill in your appId in API-Example/profile/appIdInput.asset");
    }

    private void InitEngine()
    {
    
        RtcEngine = Agora.Rtc.RtcEngine.CreateAgoraRtcEngine();

        AgoraVideoManagerHandler handler = new AgoraVideoManagerHandler(this);
        RtcEngineContext context = new RtcEngineContext(_appID, 0,
                                    CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_COMMUNICATION,
                                    AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_DEFAULT);
        //    RtcEngine.SetCameraDeviceOrientation(VIDEO_SOURCE_TYPE.VIDEO_SOURCE_CAMERA, VIDEO_ORIENTATION.VIDEO_ORIENTATION_90);
        RtcEngine.Initialize(context);
        RtcEngine.InitEventHandler(handler);
    }

    public void RegisterLocalUserAccount(string peerId)
    {
        RtcEngine.RegisterLocalUserAccount(_appID, peerId);
    }

    public void SetChinnelName(string roomid)
    {
        _channelName = roomid;
    }
    public void SetUid(string uid)
    {
      
        this.uid = StringToUint(uid);
    }

    public void JoinChannel()
    {
        Debug.Log("  JoinChannel  " + _channelName);
        RtcEngine.EnableAudio();
        RtcEngine.EnableVideo();

        // RtcEngine.DisableAudio();
        //  RtcEngine.DisableVideo();
        VideoEncoderConfiguration config = new VideoEncoderConfiguration();
        //config.dimensions = new VideoDimensions(CustomInfo.mWidth, CustomInfo.mHight);
        //config.frameRate = 15;
        //config.bitrate = 0;
        //    config.orientationMode = ORIENTATION_MODE.ORIENTATION_MODE_ADAPTIVE;
        //RtcEngine.SetVideoEncoderConfiguration(config);
        RtcEngine.SetChannelProfile(CHANNEL_PROFILE_TYPE.CHANNEL_PROFILE_COMMUNICATION);
        RtcEngine.SetClientRole(CLIENT_ROLE_TYPE.CLIENT_ROLE_BROADCASTER);
        // _channelName = roomid;
        SenderOptions s = new SenderOptions();
        RtcEngine.SetExternalVideoSource(true, true, EXTERNAL_VIDEO_SOURCE_TYPE.VIDEO_FRAME,s);
        //RtcEngine.SetRemoteDefaultVideoStreamType(VIDEO_STREAM_TYPE.VIDEO_STREAM_LOW);
        if (DeviceType.type == "DreamGlass")
            RtcEngine.SetAudioProfile(0, AUDIO_SCENARIO_TYPE.AUDIO_SCENARIO_GAME_STREAMING);
        //  RtcEngine.SetLocalVideoMirrorMode(VIDEO_MIRROR_MODE_TYPE.VIDEO_MIRROR_MODE_ENABLED);
        RtcEngine.JoinChannel(_token, _channelName, "", uid);
        Debug.Log("uid  " + uid);
        //RtcEngine.MuteLocalVideoStream(false);
        //RtcEngine.MuteLocalAudioStream(false);
        //RtcEngine.MuteAllRemoteAudioStreams(true);
        //RtcEngine.MuteAllRemoteVideoStreams(true);
        isRoom = true;
        EnableLoacalAudio(CustomInfo.isSendAudio);
        EnableLocalVideo(CustomInfo.isSendVideo);
        isSendVideo = CustomInfo.isSendVideo;
    }

    public void OpenAgoraAudio()
    {
        Debug.Log(" 打开   OpenAgoraAudio ");
        // RtcEngine.SwitchCamera();
        //RtcEngine.MuteAllRemoteAudioStreams(false);
        //RtcEngine.MuteAllRemoteVideoStreams(false);
        //   RtcEngine.EnableAudio();
    }

    Texture2D screenShot;
    public Camera ca;
    public RawImage img;
    IEnumerator RenderTexturesScreenCapture()
    {

        Debug.Log("RenderTexturesScreenCapture发送图片1");
        yield return new WaitForEndOfFrame();
        if (screenShot == null)
        {
            screenShot = new Texture2D(CustomInfo.mWidth, CustomInfo.mHight, TextureFormat.RGBA32, false);
            StartCoroutine(GetRenederFPS());
        }
        while (screenShot!=null)
        {
           // 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);
            }
        }
    }
    byte[] bts;
    IEnumerator GetRenederFPS()
    {
        while (screenShot != null)
        {
            var req = AsyncGPUReadback.Request(RemoteRtc.Instance.cam2.targetTexture);
            yield return new WaitUntil(() => req.done);
            if(screenShot!=null)
            {

                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");
                }
            }
        }
    }
    Texture2D flipTexture;


    private IEnumerator CloseChannel(float times)
    {
        yield return new WaitForSeconds(times);
        LeaveChannel();
    }

    public void LeaveChannel()
    {
        cameraStop();
        Debug.Log("LeaveChannel ");
        int msg = RtcEngine.LeaveChannel();
        switch (msg)
        {
            case 0:
                LogText.text = "成功退出频道: " + _channelName;
                break;
            default:
                LogText.text = "退出频道失败: " + msg;
                break;
        }
        isRoom = false;
        myPeer = null;
        dicPeeridAndUid.Clear();
        dicPeeridAndUid = new Dictionary<string, uint>();

        AgoraVideoAudioManager.Instance.listCustomPeer.Clear();
        AgoraVideoAudioManager.Instance.listCustomPeer = new List<CustomPeer>();


        //list_ShowView.Clear();
        //list_ShowView = new Dictionary<string, RawImage>();
        mainViewPeerId = "";
        RoomMain.Instance.agoraRawImage.gameObject.SetActive(false);
        RoomMain.Instance.agoraRawImage.texture = null;
    
       
        DestroyImmediate(RoomMain.Instance.agoraRawImage.GetComponent<UIElementDrag>());
        DestroyImmediate(RoomMain.Instance.agoraRawImage.GetComponent<VideoSurface>());
    }

    public void VuforiaLeaveChannel()
    {
        int msg = RtcEngine.LeaveChannel();
        switch (msg)
        {
            case 0:
                LogText.text = "成功退出频道: " + _channelName;
                break;
            default:
                LogText.text = "退出频道失败: " + msg;
                break;
        }
    }

    public void AddPeeridUid(string peerid, uint uid)
    {
        Debug.Log(" AddPeeridUid " + peerid + "   " + uid);

        if (dicPeeridAndUid.ContainsKey(peerid))
        {
            dicPeeridAndUid[peerid] = uid;

            return;

        }
        dicPeeridAndUid.Add(peerid, uid);
    }

    public void AddPeeridUid(string peerid, string strUid)
    {
        uint uid = StringToUint(strUid);
        Debug.Log(" AddPeeridUid " + peerid + "   " + uid);

        if (dicPeeridAndUid.ContainsKey(peerid))
        {

            dicPeeridAndUid[peerid] = uid;
            return;
        }
        dicPeeridAndUid.Add(peerid, uid);
    }

    public void RemAtPeeridUid(string peerid)
    {
        if (!dicPeeridAndUid.ContainsKey(peerid))
            return;
        Debug.Log(" RemAtPeeridUid " + peerid + "   " + dicPeeridAndUid[peerid]);
        dicPeeridAndUid.Remove(peerid);

        CloseAgoraMainImage(peerid, false);

        for (int i = 0; i < listCustomPeer.Count; i++)
        {
            if (listCustomPeer[i].peerId == peerid)
            {
                listCustomPeer.RemoveAt(i);
                break;
            }
        }
    }

    private void CloseAgoraMainImage(string peerid, bool isOpen)
    {
        if (peerid == mainViewPeerId)
            RoomMain.Instance.agoraRawImage.gameObject.SetActive(isOpen);
    }

    public void ShowLocalView(RawImage rawImage)
    {
        rawImage.gameObject.SetActive(true);
        rawImage.rectTransform.localEulerAngles = new Vector3(0, 180, 180);
        MakeVideoView(0, rawImage);
    }

    public void AddListShowView(string peerId, RawImage rawImage, bool isMainView)
    {

        if (!dicPeeridAndUid.ContainsKey(peerId))
            return;
        Debug.Log(" AddListShowView " + peerId);

        if (isMainView)
            mainViewPeerId = peerId;

        rawImage.gameObject.SetActive(true);
        rawImage.rectTransform.localEulerAngles = new Vector3(0, 180, 180);

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

    public void AddListShowView(string peerId, RawImage rawImage)
    {

        if (!dicPeeridAndUid.ContainsKey(peerId))
            return;
        Debug.Log(" AddListShowView " + peerId);

        if (rawImage.name == "AgoraRawImage")
            mainViewPeerId = peerId;

        //  rawImage.gameObject.SetActive(true);
        rawImage.rectTransform.localEulerAngles = new Vector3(0, 180, 180);

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

    public void ShowOneView(RawImage rawImage)
    {
        if (dicPeeridAndUid.Count < 2)
            return;
      //  rawImage.gameObject.SetActive(true);
        rawImage.rectTransform.localEulerAngles = new Vector3(0, 180, 180);
        MakeVideoView(dicPeeridAndUid.Values.Skip(1).First(), rawImage, this._channelName);
    }



    public void UserJoined(uint uid)
    {
        if (uid == dicPeeridAndUid.Values.Skip(1).First())
        {

          //  RoomMain.Instance.agoraRawImage.gameObject.SetActive(true);
            RoomMain.Instance.agoraRawImage.rectTransform.localEulerAngles = new Vector3(0, 180, 180);
            MakeVideoView(dicPeeridAndUid.Values.Skip(1).First(), RoomMain.Instance.agoraRawImage, this._channelName);

            foreach (var item in dicPeeridAndUid)
            {
                if (item.Value == uid)
                    mainViewPeerId = item.Key;
            }
        }

    }

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

        //  int msg = RtcEngine.EnableLocalAudio(isAudio);
        switch (msg)
        {
            case 0:
                Debug.Log(isAudio ? "打开本地音频成功" : "关闭本地音频成功 ");
                break;
            default:
                Debug.LogError("开关本地音频失败: " + msg);
                break;
        }
    }
    public void  cameraStart()
    {
        if (rc == null)
        {
            if (RemoteRtc.Instance.cam2.targetTexture != null)
                RemoteRtc.Instance.cam2.targetTexture.Release();
            RemoteRtc.Instance.cam2.targetTexture = new RenderTexture(CustomInfo.mWidth, CustomInfo.mHight, 1);
            StartCoroutine(RenderTexturesScreenCapture());
            XRRGBCamera.Instance.playCamera(CustomInfo.mWidth, CustomInfo.mHight);

        }
    }
    public void cameraStop()
    {
        XRRGBCamera.Instance.stopCamera();
        if (screenShot != null)
            Destroy(screenShot);
        screenShot = null;
        rc = null;
        bts = null;
    }
    Coroutine rc;
    public void EnableLocalVideo(bool isVideo)
    {
        if(isVideo)
        {
            cameraStart();
        }
        else
        {
            cameraStop();
        }

        int msg = RtcEngine.MuteLocalVideoStream(!isVideo);
        //RtcEngine.EnableVideo();
        //int msg = RtcEngine.EnableLocalVideo(isVideo);
        //if(isVideo)
        //    RemoteRtc.Instance.InitCamera();
        switch (msg)
        {
            case 0:
                Debug.Log(isVideo ? "打开本地视频成功 " : "关闭本地视频成功 ");
                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 MuteRemoteVideoStream(string peerid, bool isVideo)
    {
        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;
        }

        CloseAgoraMainImage(peerid, !isVideo);
    }


    public void RemoteVideoStateChanged(uint uid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON
      reason)
    {
        Debug.Log("RemoteVideoStateChanged   " + reason);
        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;
                        CloseAgoraMainImage(listCustomPeer[i].peerId, true);
                        break;
                    case REMOTE_VIDEO_STATE.REMOTE_VIDEO_STATE_DECODING:
                        listCustomPeer[i].isCloseVideo = false;
                        CloseAgoraMainImage(listCustomPeer[i].peerId, true);
                        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].isCloseVideo = true;
                        CloseAgoraMainImage(listCustomPeer[i].peerId, false);
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_LOCAL_UNMUTED://本地用户恢复接收远端视频流或本地用户启动视频模块
                      
                        listCustomPeer[i].isCloseVideo = false;
                        CloseAgoraMainImage(listCustomPeer[i].peerId, true);
                        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;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_VIDEO_STREAM_TYPE_CHANGE_TO_LOW:
                        break;
                    case REMOTE_VIDEO_STATE_REASON.REMOTE_VIDEO_STATE_REASON_VIDEO_STREAM_TYPE_CHANGE_TO_HIGH:
                        break;
                    default:
                        break;
                }
                break;
            }
        }





    }

    public void RemoteAudioStateChanged(uint uid, REMOTE_AUDIO_STATE state, REMOTE_AUDIO_STATE_REASON reason)
    {
        Debug.Log(listCustomPeer.Count);
        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)
            {
                switch (state)
                {
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_STOPPED:
                        // listCustomPeer[i].isVideo = 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].isCloseAudio = false;
                        break;
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_FROZEN:
                        break;
                    case REMOTE_AUDIO_STATE.REMOTE_AUDIO_STATE_FAILED:
                        //  listCustomPeer[i].isVideo = false;
                        break;
                    default:
                        break;
                }
                Debug.Log("RemoteAudioStateChanged   " + reason);
                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].isCloseAudio = true;
                        break;
                    case REMOTE_AUDIO_STATE_REASON.REMOTE_AUDIO_REASON_LOCAL_UNMUTED:
                        listCustomPeer[i].isCloseAudio = 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 uint StringToUint(string value)
    {
        //byte[] bytes = Encoding.ASCII.GetBytes(value);

        return (uint)int.Parse(value);
       // return BitConverter.ToUInt32(bytes);
    }
    private void StopPublish()
    {
        var options = new ChannelMediaOptions();
        options.publishMicrophoneTrack.SetValue(false);
        options.publishCameraTrack.SetValue(false);
        var nRet = RtcEngine.UpdateChannelMediaOptions(options);
        this.Log.UpdateLog("UpdateChannelMediaOptions: " + nRet);
    }

    private void StartPublish()
    {
        var options = new ChannelMediaOptions();
        options.publishMicrophoneTrack.SetValue(true);
        options.publishCameraTrack.SetValue(true);
        var nRet = RtcEngine.UpdateChannelMediaOptions(options);
        this.Log.UpdateLog("UpdateChannelMediaOptions: " + nRet);
    }

    private void OnDestroy()
    {
        Debug.Log("OnDestroy");
        if (RtcEngine == null) return;
        RtcEngine.InitEventHandler(null);
        RtcEngine.LeaveChannel();
        RtcEngine.Dispose();
    }


    internal string GetChannelName()
    {
        return _channelName;
    }

    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
        //}
       // rawImage.gameObject.SetActive(true);
        // create a GameObject and assign to this new user
        var videoSurface = MakeImageSurface(rawImage);
        // var videoSurface = MakePlaneSurface(uid.ToString());
        if (ReferenceEquals(videoSurface, null)) return;
        // configure videoSurface
        if (uid == 0)
        {
            //  videoSurface.SetForUser(uid, channelId);
        }
        else
        {
            videoSurface.SetForUser(uid, channelId, VIDEO_SOURCE_TYPE.VIDEO_SOURCE_REMOTE);
        }

        //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);
        //};

        videoSurface.SetEnable(true);
        //  AgoraVideoAudioManager.Instance.EnableLocalVideo(false);

    }

    //internal static void OnUserInfoUpdated(uint uid, Agora.Rtc.UserInfo info)
    //{
    //    Debug.Log(info.uid);
    //    disUserPeer_Uid.Add("", info);
    //}

    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))

        AgoraVideoAudioManager.Instance.UserJoined(uid);

    }

    internal static void OnRemoteVideoStateChanged(uint uid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON
        reason)
    {
        AgoraVideoAudioManager.Instance.RemoteVideoStateChanged(uid, state, reason);
    }
    internal static void OnRemoteAudioStateChanged(uint uid, REMOTE_AUDIO_STATE state, REMOTE_AUDIO_STATE_REASON reason)
    {
        AgoraVideoAudioManager.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)
    {
        //GameObject go = rawImage.gameObject;

        //if (go == null)
        //{
        //    go = new GameObject();
        //    //go.name = goName;
        //    // to be renderered onto
        //    go.AddComponent<RawImage>();
        //    // set up transform
        //    //go.transform.Rotate(0f, 0.0f, 180.0f);
        //    //go.transform.localPosition = Vector3.zero;
        //    //go.transform.localScale = new Vector3(2f, 3f, 1f);
        //}

        //if (go == null)
        //{
        //    return null;
        //}

        // make the object draggable
        if (rawImage.gameObject.GetComponent<UIElementDrag>() != null)
            Destroy(rawImage.gameObject.GetComponent<UIElementDrag>());

        rawImage.gameObject.AddComponent<UIElementDrag>();
        //var canvas = GameObject.Find("VideoCanvas");
        //if (canvas != null)
        //{
        //    go.transform.parent = canvas.transform;
        //    Debug.Log("add video view");
        //}
        //else
        //{
        //    Debug.Log("Canvas is null video view");
        //}



        // configure videoSurface

        if (rawImage.gameObject.GetComponent<VideoSurface>() != null)
            Destroy(rawImage.gameObject.GetComponent<VideoSurface>());

        var videoSurface = rawImage.gameObject.AddComponent<VideoSurface>();
        return videoSurface;
    }

    internal static void DestroyVideoView(uint uid)
    {
        var go = GameObject.Find(uid.ToString());
        if (!ReferenceEquals(go, null))
        {
            Destroy(go);
        }
    }



    internal static void OnUserInfoUpdated(uint uid, Agora.Rtc.UserInfo info)
    {
        Debug.Log(uid.ToString() + "  " + info.uid + "  " + info.userAccount);
        //   list_UserInfo.Add(info);

    }

    internal static void OnLocalUserRegistered(uint uid, string userAccount)
    {
        //AgoraVideoAudioManager.Instance.uid = uid;
        //AgoraVideoAudioManager.Instance.userAccount = userAccount;
    }

    #endregion
}

#region -- Agora Event ---

public class AgoraVideoManagerHandler : IRtcEngineEventHandler
{
    private readonly AgoraVideoAudioManager _videoSample;

    internal AgoraVideoManagerHandler(AgoraVideoAudioManager videoSample)
    {
        _videoSample = videoSample;
    }

    public override void OnError(int err, string msg)
    {
        _videoSample.Log.UpdateLog(string.Format("OnError err: {0}, msg: {1}", err, msg));
    }

    public override void OnJoinChannelSuccess(RtcConnection connection, int elapsed)
    {
        int build = 0;
        Debug.Log("Agora: OnJoinChannelSuccess ");
        _videoSample.Log.UpdateLog(string.Format("sdk version: ${0}",
            _videoSample.RtcEngine.GetVersion(ref build)));
        _videoSample.Log.UpdateLog(string.Format("sdk build: ${0}",
          build));
        _videoSample.Log.UpdateLog(
            string.Format("OnJoinChannelSuccess channelName: {0}, uid: {1}, elapsed: {2}",
                            connection.channelId, connection.localUid, elapsed));

        //  _videoSample.ClickSelf();
        // AgoraVideoAudioManager.MakeVideoView(0);

    }

    public override void OnLeaveChannel(RtcConnection connection, RtcStats stats)
    {
        _videoSample.Log.UpdateLog("OnLeaveChannel");
        AgoraVideoAudioManager.DestroyVideoView(0);
    }

    public override void OnClientRoleChanged(RtcConnection connection, CLIENT_ROLE_TYPE oldRole, CLIENT_ROLE_TYPE newRole)
    {
        _videoSample.Log.UpdateLog("OnClientRoleChanged");
    }

    public override void OnUserJoined(RtcConnection connection, uint uid, int elapsed)
    {
        Debug.Log(string.Format("OnUserJoined uid: ${0} elapsed: ${1}", uid, elapsed));
        _videoSample.Log.UpdateLog(string.Format("OnUserJoined uid: ${0} elapsed: ${1}", uid, elapsed));
        AgoraVideoAudioManager.OnUserJoined(uid);
        //   AgoraVideoAudioManager.MakeVideoView(uid, _videoSample.GetChannelName());
    }

    public override void OnUserOffline(RtcConnection connection, uint uid, USER_OFFLINE_REASON_TYPE reason)
    {
        _videoSample.Log.UpdateLog(string.Format("OnUserOffLine uid: ${0}, reason: ${1}", uid,
            (int)reason));
        //  AgoraVideoAudioManager.DestroyVideoView(uid);
    }

    public override void OnUserInfoUpdated(uint uid, Agora.Rtc.UserInfo info)
    {
        _videoSample.Log.UpdateLog(string.Format(" 用户 :${0}  加入房间", uid));

        AgoraVideoAudioManager.OnUserInfoUpdated(uid, info);
    }


    public override void OnUplinkNetworkInfoUpdated(UplinkNetworkInfo info)
    {
        _videoSample.Log.UpdateLog("OnUplinkNetworkInfoUpdated");
    }

    public override void OnDownlinkNetworkInfoUpdated(DownlinkNetworkInfo info)
    {
        _videoSample.Log.UpdateLog("OnDownlinkNetworkInfoUpdated");
    }



    public override void OnRemoteVideoStateChanged(RtcConnection connection, uint remoteUid, REMOTE_VIDEO_STATE state, REMOTE_VIDEO_STATE_REASON reason, int elapsed)
    {
        AgoraVideoAudioManager.OnRemoteVideoStateChanged(remoteUid, state, reason);
    }

    public override void OnRemoteAudioStateChanged(RtcConnection connection, uint remoteUid, REMOTE_AUDIO_STATE state, REMOTE_AUDIO_STATE_REASON reason, int elapsed)
    {
        AgoraVideoAudioManager.OnRemoteAudioStateChanged(remoteUid, state, reason);
    }
}

#endregion