package cn.tee3.dev.activity;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.media.projection.MediaProjectionManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import rtc.AVDEngine;
import rtc.Device;
import rtc.ErrorCode;
import rtc.MAudio;
import rtc.MChat;
import rtc.MScreen;
import rtc.MUserManager;
import rtc.MVideo;
import rtc.MWhiteboard;
import rtc.Room;
import rtc.RoomInfo;
import rtc.Tlog;
import rtc.User;
import rtc.WhiteboardView;
import rtc.webrtc.ScreenCapturerAndroid;
import cn.tee3.dev.R;
import cn.tee3.dev.activity.view.T3VideoView;
import cn.tee3.dev.activity.view.UserRecyclerViewAdapter;

/**
 * 两人视频会议demo：
 *  - 对方发布的摄像头视频和共享的屏幕，共用一个窗口显示，且优先显示共享屏幕视频。
 */
public class MeetingActivity extends Activity implements View.OnClickListener {

    private LinearLayout llCamera;
    private LinearLayout llMicrophone;
    private LinearLayout llSwitch;
    private LinearLayout llUsers;
    private LinearLayout llUsersList;
    private LinearLayout llWhiteboard;
    private LinearLayout llScreen;
    private RecyclerView recyclerView;
    private ImageView ivCamera;
    private ImageView ivMicrophone;
    private String roomId;
    private Room room;
    private MVideo mVideo;
    private MScreen mScreen;
    private MWhiteboard mWhiteboard;
    private MUserManager mUserManager;
    private MAudio mAudio;

    private List<T3VideoView> videoViewList = new ArrayList<>();
    private MVideo.CameraType defaultCamera = MVideo.CameraType.front;
    private MyHandler myHandler = new MyHandler();
    private UserRecyclerViewAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_meeting);

        initView();
        displayVideo(); // 加载视频
    }

    private void initView() {
        llCamera = findViewById(R.id.ll_camera);
        llMicrophone = findViewById(R.id.ll_microphone);
        llSwitch = findViewById(R.id.ll_switch);
        llUsers = findViewById(R.id.ll_users);
        llUsersList = findViewById(R.id.ll_usersList);
        llWhiteboard = findViewById(R.id.ll_whiteboard);
        llScreen = findViewById(R.id.ll_screen);
        recyclerView = findViewById(R.id.recyclerView_users);

        ivCamera = findViewById(R.id.iv_camera);
        ivMicrophone = findViewById(R.id.iv_microphone);

        llCamera.setOnClickListener(this);
        llMicrophone.setOnClickListener(this);
        llSwitch.setOnClickListener(this);
        llUsers.setOnClickListener(this);
        llWhiteboard.setOnClickListener(this);
        llScreen.setOnClickListener(this);

        videoViewList.add(findViewById(R.id.video_01));
        videoViewList.add(findViewById(R.id.video_02));
        videoViewList.add(findViewById(R.id.video_03));
        videoViewList.add(findViewById(R.id.video_04));
        for (T3VideoView videoView : videoViewList) {
            videoView.setImageResource(R.drawable.img_novideo_bg);  // 设置视频窗口未渲染视频时的占位图片
        }

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    }

    /**
     * 初始化视频以及显示
     */
    private void displayVideo() {
        Intent intent = getIntent();
        roomId = intent.getStringExtra("ROOM_ID");
        room = Room.obtain(roomId);
        // 获取房间为空或者房间未工作则退出
        if (room == null || !room.isWorking()) {
            finish();
            return;
        }
        room.setListener(roomListener);     // 设置房间监听
        mVideo = MVideo.getVideo(room);     // 获取视频处理对象
        mScreen = MScreen.getScreen(room);  // 获取共享屏幕对象
        mAudio = MAudio.getAudio(room);     // 获取音频处理对象
        mWhiteboard = MWhiteboard.getWhiteboard(room);      // 获取白板对象
        mUserManager = MUserManager.getUserManager(room);   // 获取用户管理对象
        mAudio.setHandFree(true);   // true: 使用外放 ， false: 使用听筒

        // 设置相应回调
        mVideo.setListener(videoListener);
        mScreen.setListener(screenListener);
        mUserManager.setListener(userManagerListener);
        mAudio.setListener(audioListener);

        initWhiteboard();   // 初始化白板
        subscribeVideos();  // 订阅已发布视频（只订阅3路视频，不包含自己）
    }

    /**
     * 显示参会者列表
     */
    private void showHideUserList() {
        if (llUsersList.getVisibility() == View.VISIBLE) {
            llUsersList.setVisibility(View.GONE);
        } else {
            llUsersList.setVisibility(View.VISIBLE);
            if (adapter == null) {
                recyclerView.setHasFixedSize(true);
                LinearLayoutManager layoutManager = new LinearLayoutManager(this);
                recyclerView.setLayoutManager(layoutManager);
                adapter = new UserRecyclerViewAdapter(this, getMeetingUsers());
                recyclerView.setAdapter(adapter);
            }
            // 1秒钟更新一次列表
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (llUsersList.getVisibility() == View.VISIBLE) {
                        adapter.updateUserList(getMeetingUsers());
                        new Handler().postDelayed(this, 500);
                    }
                }
            }, 1000);
        }
    }

    /**
     * 获取房间用户列表，第一个元素是自己。
     */
    public List<User> getMeetingUsers() {
        if (mUserManager == null) {
            return new ArrayList<>();
        }
        List<User> userList = new ArrayList<>();
        if (mUserManager != null) {
            userList.add(mUserManager.getSelfUser());   // 获取自己的用户对象并添加到列表头部
            userList.addAll(mUserManager.getParticipants(0, mUserManager.getParticipantsCount()));  // 获取并添加参会者列表（mUserManager获取的列表不包含自己）
        }
        return userList;
    }

    /**
     * 查找空闲的未做渲染的视频窗口
     */
    private T3VideoView findFreeRender(List<T3VideoView> videoViewList) {
        for (T3VideoView videoView : videoViewList) {
            if (videoViewList.indexOf(videoView) != 0 && !videoView.hasVideo()) {
                return videoView;
            }
        }
        return null;
    }

    /**
     * 查找正在显示传入视频的窗口
     */
    private T3VideoView findVideoView(List<T3VideoView> videoViewList, String videoId) {
        if (TextUtils.isEmpty(videoId)) {
            return null;
        }
        for (T3VideoView videoView : videoViewList) {
            if (videoView.hasVideo() && videoId.equals(videoView.getVideoId())) {
                return videoView;
            }
        }
        return null;
    }

    /**
     * 订阅已发布的视频，小于等于3
     */
    private void subscribeVideos() {
        List<MVideo.Camera> cameraList = mVideo.getPublishedCameras();  // 获取已发布的视频列表

        for (int i = 0; i < (Math.min(cameraList.size(), 3)); i++) {
            mVideo.subscribe(cameraList.get(i).getId());    // 订阅视频
        }
    }

    /**
     * 渲染视频到窗口
     */
    private void attachRender(T3VideoView videoView, String videoId) {
        if (videoView != null) {
            Tlog.w("Application", "attachRender -> T3VideoView: " + videoView.hashCode());
            videoView.setVideo(videoId);    // 设置窗口设备id用于布局显示
            mVideo.attachRender(videoId, videoView.getRender());    // 渲染视频
        }
    }

    /**
     * 停止渲染
     */
    public void detachRender(T3VideoView videoView) {
        if (videoView != null && !videoView.hasVideo()) {
            return;
        }

        mVideo.detachRender(videoView.getRender()); // 停止渲染
        videoView.setVideo(null);
    }

    /**
     * 打开/关闭摄像头
     */
    public void openCloseCamera() {
        if (mVideo == null) {
            return;
        }
        int ret;
        if (mVideo.isCameraPublished(defaultCamera)) {
            ret = mVideo.unpublishLocalCamera();    // 停止发布本地摄像头
        } else {
            ret = mVideo.publishLocalCamera(defaultCamera); // 发布本地摄像头
        }

        if (ret != ErrorCode.AVD_OK) {
            Message msg = Message.obtain();
            msg.obj = EventType.CAMERA;
            msg.arg1 = ret;
            myHandler.sendMessage(msg);
        }
    }

    /**
     * 打开/关闭麦克风
     */
    public void openCloseMicrophone() {
        if (mAudio == null) {
            return;
        }
        int ret;
        if (mAudio.isOpenMicrophone()) {
            ret = mAudio.closeMicrophone(); // 关闭麦克风
        } else {
            ret = mAudio.openMicrophone();  // 打开麦克风
        }

        if (ret != ErrorCode.AVD_OK) {
            Message msg = Message.obtain();
            msg.obj = EventType.MICROPHONE;
            msg.arg1 = ret;
            myHandler.sendMessage(msg);
        }
    }

    /**
     * 前后摄像头切换
     */
    public void frontBackCameraSwitch() {
        if (mVideo == null) {
            return;
        }
        defaultCamera = (defaultCamera == MVideo.CameraType.front) ? MVideo.CameraType.back : MVideo.CameraType.front;
        mVideo.switchToLocalCamera();   // 前后摄像头切换
    }

    /**
     * 打开/关闭共享屏幕
     */
    public void openCloseScreen() {
        if (mScreen == null) {
            return;
        }
        if (mScreen.hasScreenPublished()) {
            Toast.makeText(MeetingActivity.this, "关闭共享屏幕", Toast.LENGTH_SHORT).show();
            mScreen.unpublishedScreens();
        } else {
            Toast.makeText(MeetingActivity.this, "打开共享屏幕", Toast.LENGTH_SHORT).show();
            startScreenCapture();
        }
    }

    /***********************************************    房间管理示例 ********************************************************************* */
    public Room.Listener roomListener = new Room.Listener() {
        @Override
        public void onJoinResult(int result) {

        }

        @Override   /** 被迫离会通知 */
        public void onLeaveIndication(int reason, String fromId) {
            Toast.makeText(MeetingActivity.this, "踢出房间：" + reason, Toast.LENGTH_LONG).show();
            finish();
        }

        @Override
        public void onPublicData(byte[] data, int len, String fromId) {

        }

        @Override
        public void onPrivateData(byte[] data, int len, String fromId) {

        }

        @Override
        public void onAppDataNotify(String key, String value) {

        }

        @Override
        public void onRoomStatusNotify(RoomInfo.RoomStatus status) {

        }

        @Override   /** 断线重连通知 */
        public void onConnectionStatus(Room.ConnectionStatus status) {
            if (status == Room.ConnectionStatus.connecting) {
                Toast.makeText(MeetingActivity.this, "断线重连中。。。", Toast.LENGTH_LONG).show();
            } else if (status == Room.ConnectionStatus.connectFailed){
                Toast.makeText(MeetingActivity.this, "断线重连失败，离会！", Toast.LENGTH_LONG).show();
                finish();
            }
        }

        @Override
        public void onOutgoingInviteStatusNotify(int type, String roomId, String addr, int status, String amsg) {

        }

        @Override
        public void onStreamKeepAliveTimeoutNotify(String userId, String userName, int mediaType, String deviceId, int ssrc) {

        }
    };

    /***********************************************    摄像头视频示例 ******************************************************************* */
    MVideo.Listener videoListener = new MVideo.Listener() {
        @Override
        public void onCameraStatusNotify(Device.DeviceStatus status, String fromId) {

        }

        @Override
        public void onCameraDataNotify(int level, String description, String fromId) {

        }

        @Override   /** 发布视频回调 */
        public void onPublishCameraNotify(MVideo.Camera camera) {
            T3VideoView videoView = findFreeRender(videoViewList);
            if (videoView != null && !mUserManager.isSelfDevice(camera.getId())) {
                mVideo.subscribe(camera.getId());   // 不是自己的视频则订阅，会触发 onSubscribeResult 回调，在订阅回调中渲染视频。
            }
        }

        @Override  /** 停止发布视频回调 */
        public void onUnpublishCameraNotify(MVideo.Camera camera) {
            if (!mUserManager.isSelfDevice(camera.getId())) {
                mVideo.unsubscribe(camera.getId()); // 不是自己的视频则取消订阅，会触发 onUnsubscribeResult 回调，在停止订阅回调中停止渲染视频。
                T3VideoView videoView = findVideoView(videoViewList, camera.getId());
                detachRender(videoView);    // 停止渲染视频
            }
        }

        @Override  /** 订阅视频回调 */
        public void onSubscribeResult(int result, String fromId) {
            if (result == ErrorCode.AVD_OK) {
                T3VideoView videoView = findFreeRender(videoViewList);
                attachRender(videoView, fromId);    // 渲染视频
            }
        }

        @Override  /** 停止订阅视频回调 */
        public void onUnsubscribeResult(int result, String fromId) {
        }

        @Override     /** 发布本地视频回调 */
        public void onPublishLocalResult(int result, String fromId) {
            Message msg = Message.obtain();
            msg.obj = EventType.CAMERA;
            msg.arg1 = result;
            myHandler.sendMessage(msg);
            if (result == ErrorCode.AVD_OK) {
                attachRender(videoViewList.get(0), fromId); // 将自己的视频渲染到第一个窗口
            }
        }

        @Override  /** 停止发布本地视频回调 */
        public void onUnpublishLocalResult(int result, String fromId) {
            Message msg = Message.obtain();
            msg.obj = EventType.CAMERA;
            msg.arg1 = result;
            myHandler.sendMessage(msg);
            if (result == ErrorCode.AVD_OK) {
                detachRender(videoViewList.get(0)); // 停止渲染自己的视频
            }
        }
    };

    /***********************************************    共享屏幕示例 ********************************************************************* */
    MScreen.Listener screenListener = new MScreen.Listener() {
        @Override
        public void onScreenStatusNotify(Device.DeviceStatus status, String fromId) {

        }

        @Override
        public void onScreenDataNotify(int level, String description, String fromId) {

        }

        @Override   /** 发布共享屏幕回调 */
        public void onPublishScreenNotify(MScreen.ScreenWindow screen) {
            if (!mUserManager.isSelfDevice(screen.getId())) {
                mScreen.subscribe(screen.getId());  // 订阅非自己的共享屏幕，会触发 onSubscribeResult 回调，在 onSubscribeResult 做渲染视频操作。
            }
        }

        @Override   /** 发布本地共享屏幕回调 */
        public void onPublishScreenResult(int result, String screenId) {
        }

        @Override   /** 停止发布共享屏幕回调 */
        public void onUnpublishScreenNotify(MScreen.ScreenWindow screen) {
            if (!mUserManager.isSelfDevice(screen.getId())) {
                mScreen.unsubscribe(screen.getId());  // 取消订阅非自己的共享屏幕，会触发 onUnsubscribeResult 回调，在 onUnsubscribeResult 做停止渲染视频操作。
            }
        }

        @Override   /** 取消发布本地共享屏幕回调 */
        public void onUnpublishScreenResult(int result, String screenId) {
        }

        @Override   /** 订阅共享屏幕回调 */
        public void onSubscribeResult(int result, String fromId) {
            if (result == ErrorCode.AVD_OK) {
                T3VideoView videoView = findFreeRender(videoViewList);
                attachRender(videoView, fromId);
            }
        }

        @Override   /** 取消订阅共享屏幕回调 */
        public void onUnsubscribeResult(int result, String fromId) {
            if (result == ErrorCode.AVD_OK) {
                T3VideoView videoView = findVideoView(videoViewList, fromId);
                detachRender(videoView);
            }
        }
    };

    /**
     * 共享本地屏幕
     */
    @TargetApi(21)
    private void startScreenCapture() {
        ScreenCapturerAndroid.configureContext(this);   // 配置当前activity上下文，用于共享屏幕自适应屏幕方向，否则竖屏发布共享屏幕，而后切换手机为横屏时发布的视频宽高比还是竖屏的宽高比。
        MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE);
        startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), 1);
    }

    @TargetApi(21)
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        mVideo.sendScreenIntent(data);

        /** 1. 共享全屏 */
        mScreen.publishedScreens(MScreen.ScreenResolution.SCREEN_720P, 20, true);

        /** 2. 共享屏幕的指定区域 */
//        ScaleScreenCapturer.ScaleZone scaleZone = new ScaleScreenCapturer.ScaleZone(0,    // 起始x坐标
//                                                                                    0,     // 起始y坐标
//                                                                                    300,    // 截图区域宽度
//                                                                                    300); // 截图区域高度
//        MeetingManager.getInstance().getScreen().publishedScreens(MScreen.ScreenResolution.SCREEN_720P, 15, false);
//        MeetingManager.getInstance().getScreen().publishScaleScreen(scaleZone);
    }

    /***********************************************    共享白板示例 ********************************************************************* */
    MWhiteboard.Listener whiteboardListener = new MWhiteboard.Listener() {
        @Override
        public void onCreateBoardNotify(MWhiteboard.Whiteboard board) {
        }

        @Override
        public void onRemoveBoardNotify(String bid) {
        }

        @Override
        public void onUpdateBoardNotify(MWhiteboard.Whiteboard board) {

        }

        @Override
        /** 共享白板(包含自己) */
        public void onShareBoardNotify(MWhiteboard.Whiteboard board) {
        }

        @Override
        /** 关闭白板(包含自己) */
        public void onCloseBoardNotify(String bid) {
        }

        @Override
        /** 创建白板异步回调通知：返回result为0代表创建白板成功，result 不为0代表创建失败，需联系管理员开通白板权限。 */
        public void onCreateLocalBoardNotify(int result, String boardId) {
            if (result == 0) {
                mWhiteboard.shareLocalWhiteBoard(boardId);  // 创建白板成功后再将白板共享到房间里
            }
        }
    };

    /**
     * 初始化白板
     */
    private void initWhiteboard() {
        WhiteboardView whiteboardView = findViewById(R.id.whiteboardView);
        whiteboardView.setWhiteboardColor(Color.WHITE);   // 设置画布背景色
        whiteboardView.setBackgroundColor(Color.BLACK);   // 设置整个白板布局背景色
        mWhiteboard.showToolbar(true)               // 设置显示白板工具栏
                .onAttachView(whiteboardView)       // 绑定白板布局
                .setListener(whiteboardListener);   // 设置监听

        mWhiteboard.getAnnotation().clearAnnotations(mWhiteboard.getLocalWhiteboardId());
    }

    /***********************************************    用户管理示例 ********************************************************************* */
    MUserManager.Listener userManagerListener = new MUserManager.Listener() {
        @Override
        public void onUserJoinNotify(User user) {

        }

        @Override
        public void onUserLeaveNotify(User user) {
        }

        @Override
        public void onUserLeaveNotify(int reason, User user) {

        }

        @Override
        public void onUserUpdateNotify(User user) {

        }

        @Override
        public void onUserStatusNotify(int status, String fromId) {

        }

        @Override
        public void onUserDataNotify(String userData, String fromId) {

        }
    };

    /***********************************************    音频相关示例 ********************************************************************* */
    MAudio.Listener audioListener = new MAudio.Listener() {
        @Override
        public void onMicrophoneStatusNotify(Device.DeviceStatus status, String fromUserId) {

        }

        @Override
        public void onAudioLevelMonitorNotify(MAudio.AudioInfo info) {

        }

        @Override
        public void onOpenMicrophoneResult(int result) {
            Message msg = Message.obtain();
            msg.obj = EventType.MICROPHONE;
            msg.arg1 = result;
            myHandler.sendMessage(msg);
        }

        @Override
        public void onCloseMicrophoneResult(int result) {
            Message msg = Message.obtain();
            msg.obj = EventType.MICROPHONE;
            msg.arg1 = result;
            myHandler.sendMessage(msg);
        }

        @Override
        public void onAudioData(String userId, long timestamp, int sampleRate, int channels, byte[] data, int len) {

        }

        @Override
        public void onMediaPlayNotify(String roomId, String playingMediaId, String userId, int playEvent) {

        }

        @Override
        public void onMediaPlayProgressNotify(int i) {

        }
    };

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.ll_camera:        // 开关摄像头
                openCloseCamera();
                break;
            case R.id.ll_microphone:    // 开关麦克风
                openCloseMicrophone();
                break;
            case R.id.ll_switch:        // 前后摄像头切换
                frontBackCameraSwitch();
                break;
            case R.id.ll_users:        // 查看用户列表
                showHideUserList();
                break;
            case R.id.ll_screen:        // 共享、停止屏幕
                openCloseScreen();
                break;
            case R.id.ll_whiteboard:   // 共享、停止白板
                if (mWhiteboard.hasLocalWhiteboardShared()) {
                    mWhiteboard.removeBoard(mWhiteboard.getLocalWhiteboardId());  // 关闭白板
                } else {
                    // 创建白板，这里设置发布出去的白板颜色为白色；创建白板会触发 onCreateLocalBoardNotify 异步回调通知，返回result为0代表创建白板成功，result 不为0代表创建失败，需联系管理员开通白板权限。
                    mWhiteboard.createLocalWhiteboard("test", "test", Color.WHITE);
                }
                break;
        }
    }

    @Override
    public void onBackPressed() {
        if (llUsersList.getVisibility() == View.VISIBLE) {
            llUsersList.setVisibility(View.GONE);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myHandler.removeCallbacksAndMessages(null);
        if (AVDEngine.instance().isWorking()) {
            AVDEngine.instance().uninit();  // 注销SDK引擎
        }
    }

    private enum EventType {
        CAMERA,
        MICROPHONE
    }

    @SuppressLint("HandlerLeak")
    private class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            EventType eventType = (EventType) msg.obj;
            switch (eventType) {
                case CAMERA:    /** 开关摄像头事件通知 */
                    if (msg.arg1 != ErrorCode.AVD_OK) {
                        Toast.makeText(MeetingActivity.this, (mVideo.isCameraPublished(defaultCamera) ? "关闭" : "打开") + "摄像头失败：" + msg.arg1, Toast.LENGTH_SHORT).show();
                    } else {
                        ivCamera.setImageResource(mVideo.ispublishedLocalCamera() ? R.drawable.img_open_camera : R.drawable.img_close_camera); // 更新摄像头图标
                    }
                    break;
                case MICROPHONE:    /** 开关麦克风事件通知 */
                    if (msg.arg1 != ErrorCode.AVD_OK) {
                        Toast.makeText(MeetingActivity.this, (mVideo.isCameraPublished(defaultCamera) ? "关闭" : "打开") + "麦克风失败：" + msg.arg1, Toast.LENGTH_SHORT).show();
                    } else {
                        ivMicrophone.setImageResource(mAudio.isOpenMicrophone() ? R.drawable.img_open_microphone : R.drawable.img_close_microphone); // 更新麦克风图标
                    }
                    break;
            }
        }
    }
}
