package cn.tee3.avd;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.annotation.Nullable;

/**
 * 用户管理接口类
 *
 * 用户管理接口定义了房间内所有用户和用户列表相关的功能操作。
 */
public class MUserManager  extends Module {
    private static final String TAG = "MUserManager";
    /**
     * 用户管理回调接口类
     *
     * 用户管理回调接口定义了房间用户和用户列表操作的异步返回，房间用户通知。
     */
    public static interface Listener {
        /// 通知
        /** 用户加入房间通知
         *
         * @param[in] user 用户信息数据。
         *
         * @note 某用户调用房间中的join加入房间后，房间内所有用户会接收到此通知
         * @sa join
         */
        public void onUserJoinNotify(User user);
        /** 用户离开房间通知
         *
         * @param[in] user 用户信息数据。
         *
         * @note 某用户调用房间中的leave离开房间后，房间内所有用户会接收到此通知
         * @sa leave
         */
        public void onUserLeaveNotify(User user);
        /**
         * 用户异常离开房间通知
         * @param reason 用户离会原因，0代表正常离会，非0异常离会。
         * @param user 用户信息数据
         */
        public void onUserLeaveNotify(int reason, User user);
        /** 用户信息更改通知
         *
         * @param[in] user 用户信息数据。
         *
         * @note 某用户调用updateUser更改自己信息后，房间内所有用户会接收到此通知
         * @sa updateUser
         */
        public void onUserUpdateNotify(User user);
        /** 用户状态更改通知
         *
         * @param[in] status 当前用户状态。
         * @param[in] fromId 关联的用户Id。
         *
         * @note 某用户调用updateSelfUserStatus更改自己状态后，房间内所有用户会接收到此通知；
         *       此通知从onUserUpdateNotify中分离出来，因用户状态更改较为频繁
         * @sa updateSelfUserStatus
         * @sa onUserUpdateNotify
         */
        public void onUserStatusNotify(int status, String fromId);
        /** 用户应用层数据更改通知
         *
         * @param[in] userData 当前用户应用层数据。
         * @param[in] fromId 关联的用户Id。
         *
         * @note 某用户调用updateSelfUserData更改自己应用层数据后，房间内所有用户会接收到此通知
         *       此通知从onUserUpdateNotify中分离出来，因应用层数据用户较为关注
         * @sa updateSelfUserData
         * @sa onUserUpdateNotify
         */
        public void onUserDataNotify(String userData, String fromId);
    }
    ///
    private long nativeListener = 0;
    @Nullable private Listener listener4cb = null;
    @Nullable private Handler listenerHandler = null;
    @Nullable private SDKListener listener4native = null;
    ///
    /** 获取房间内用户管理模块接口
     *
     * @param[in] room 房间对象指针。
     *
     * @return 返回用户管理模块接口指针。
     */
    @Nullable public static MUserManager getUserManager(Room room) {
        return (MUserManager)room.getModule(Type.usermanager);
    }
    protected MUserManager(Room room) {
        super(room, Type.usermanager, room.nativegetMUserManager());
        Tlog.d(TAG, "UserManager, nativeUserManager:" + this.nativeobj);
        initNativeListener();
    }
    @Override
    protected void dispose() {
        if (0 != this.nativeListener) {
            nativeFreeListener(this.nativeListener);
        }
        this.nativeListener = 0;
        this.nativeobj = 0;
    }

    //
    /** 设置用户管理回调接口
     *
     * @param[in] listener 回调接口指针。
     *
     * @return 返回错误代码。
     * @see Listener
     */
    public boolean setListener(Listener listener) {
        Tlog.d(TAG, "setListener, listener:" +listener+",listener4native="+this.listener4native+",listenerHandler="+this.listenerHandler);
        this.listener4cb = listener;
        if (null != listener) {
            initNativeListener();
        }
        Tlog.v(TAG, "setListener, out");
        return true;
    }
    private void initNativeListener() {
        if (0 != this.nativeListener) {
            return;
        }
        initHandler();
        this.nativeListener = nativeCreateListener(listener4native);
        Tlog.d(TAG, "initNativeListener, Create nativelistener:" + nativeListener);
    }
    /** 更新本用户信息
     *
     * @param[in] user 用户信息。
     *
     * @return 返回错误代码。
     */
    public int updateUser(User user) {
        return nativeupdateUser(user);
    }
    /** 判断用户是否存在
     *
     * @param[in] userId 用户Id。
     *
     * @return 是否存在用户。
     */
    public boolean hasUser(String userId) {
        return nativehasUser(userId);
    }
    /** 获取关联Id的用户信息
     *
     * @param[in] userId 用户Id。
     *
     * @return 返回关联Id的用户信息。
     */
    public User getUser(String userId) {
        User user = nativegetUser(userId);
        return user;
    }
    /** 获取主持人信息
     * @return 返回主持人信息。
     */
    public User getHost() {
        return nativegetHost();
    }
    /** 获取本用户信息
     * @return 返回本用户信息。
     */
    public User getSelfUser() {
        User user = nativegetSelfUser();
        return user;
    }
    /** 获取本用户Id
     * @return 返回本用户Id。
     */
    public String getSelfUserId() {
        return nativegetSelfUserId();
    }
    /** 获取本用户应用层数据
     * @return 返回本用户应用层数据。
     */
    public String getSelfUserData() {
        return nativegetSelfUserData();
    }
    /** 更改本用户的应用层数据
     *
     * @param[in] userData 本用户应用层数据。
     * @return 返回错误代码。
     */
    public int updateSelfUserData(String userData) {
        return nativeupdateSelfUserData(userData);
    }
    /** 更新某一用户名
     *
     * @param[in] userId 被更改的用户Id。
     * @param[in] newUserName 新的用户名。
     *
     * @return 返回错误代码。
     */
    public int updateUserName(String userId, String newUserName) {
        return nativeupdateUserName(userId, newUserName);
    }
    /** 更改本用户的用户状态
     *
     * @param[in] status 用户状态。
     * @return 返回错误代码。
     */
    public int updateSelfUserStatus(int status) {
        return nativeupdateSelfUserStatus(status);
    }
    /** 获取房间中的用户数量
     * @return 返回本用户数量。
     */
    public int getParticipantsCount() {
        return nativegetParticipantsCount();
    }
    /** 获取房间中的用户列表
     *
     * @param[in] begindex 起始索引。
     * @param[in] ncount 请求数量；实际返回数量。
     * @note 用户列表不包含本用户。
     * @return 返回用户列表。
     */
    public List<User> getParticipants(int begindex, int ncount) {
        List<User> users = nativegetParticipants(begindex, ncount);
        Tlog.d(TAG, "getParticipants, count=" + (null == users ? 0 : users.size()));
        if (users == null) {
            return new ArrayList<>();
        } else if (users.size() >= 2) {
            //排序，讲有视频的用户拍前面
            Collections.sort(users, new Comparator<User>() {
                @Override
                public int compare(User o1, User o2) {
                    if (o1.getStatus().isVideoOn() && !o2.getStatus().isVideoOn()) {
                        return -1;
                    }
                    if (!o1.getStatus().isVideoOn() && o2.getStatus().isVideoOn()) {
                        return 1;
                    } else {
                        return 0;
                    }
                }
            });
        }
        return users;
    }
    ///
    private native long nativeCreateListener(Listener listener);
    private native void nativeFreeListener(long nativeListener);
    private native int  nativeupdateUser(User user);
    private native boolean nativehasUser(String userId);
    private native User nativegetUser(String userId);
    private native User nativegetHost();
    private native User nativegetSelfUser();
    private native String nativegetSelfUserId();
    private native String nativegetSelfUserData();
    private native int nativeupdateSelfUserData(String value);
    private native int nativeupdateUserName(String userId, String newUserName);
    private native int nativeupdateSelfUserStatus(int status);
    private native int nativegetParticipantsCount();
    private native List<User> nativegetParticipants(int tsbegin, int ncount);

    ///
    private static final int msg_onUserJoinNotify = 1;
    private static final int msg_onUserLeaveNotify = 2;
    private static final int msg_onUserUpdateNotify = 3;
    private static final int msg_onUserStatusNotify = 4;
    private static final int msg_onUserDataNotify = 5;
    private static final int msg_onUserLeaveExceptionNotify = 6;
    private boolean initHandler() {
        if (null == listener4native) {
            listener4native = new SDKListener();
        }
        if (null != listenerHandler) {
            return true;
        }
        AVDEngine.runOnLoopThreadSync(new Runnable() {
            @Override
            public void run() {
                initHandler_main();
            }
        });
        return true;
    }
    private boolean initHandler_main() {
        this.listenerHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                Tlog.v(TAG, "handleMessage, msg:" + msg.toString());
                if (null == listener4cb) {
                    super.handleMessage(msg);
                    return;
                }
                switch (msg.what) {
                    case msg_onUserJoinNotify:
                        listener4cb.onUserJoinNotify((User) msg.obj);
                        break;
                    case msg_onUserLeaveNotify:
                        listener4cb.onUserLeaveNotify((User) msg.obj);
                        break;
                    case msg_onUserLeaveExceptionNotify:
                        listener4cb.onUserLeaveNotify(msg.arg1, (User) msg.obj);
                        break;
                    case msg_onUserUpdateNotify:
                        listener4cb.onUserUpdateNotify((User) msg.obj);
                        break;
                    case msg_onUserStatusNotify:
                        listener4cb.onUserStatusNotify(msg.arg1, (String) msg.obj);
                        break;
                    case msg_onUserDataNotify:
                        listener4cb.onUserDataNotify(
                                msg.getData().getString("userData"), msg.getData().getString("fromId"));
                        break;
                }
                super.handleMessage(msg);
            }
        };
        return true;
    }
    private class SDKListener implements Listener {
        public SDKListener() {
        }
        @Override
        public void onUserJoinNotify(User user) {
            if (null == listenerHandler) {
                return ;
            }
            Message msg = Message.obtain(listenerHandler,msg_onUserJoinNotify, user);
            listenerHandler.sendMessage(msg);
        }
        @Override
        public void onUserLeaveNotify(User user) {
            if (null == listenerHandler) {
                return ;
            }
            Message msg = Message.obtain(listenerHandler, msg_onUserLeaveNotify, user);
            listenerHandler.sendMessage(msg);
        }

        @Override
        public void onUserLeaveNotify(int reason, User user) {
            if (null == listenerHandler) {
                return ;
            }
            Message msg = Message.obtain(listenerHandler, msg_onUserLeaveExceptionNotify, reason, reason, user);
            listenerHandler.sendMessage(msg);
        }

        @Override
        public void onUserUpdateNotify(User user) {
            if (null == listenerHandler) {
                return ;
            }
            Message msg = Message.obtain(listenerHandler,msg_onUserUpdateNotify, user);
            listenerHandler.sendMessage(msg);
        }
        @Override
        public void onUserStatusNotify(int status, String fromId) {
            if (null == listenerHandler) {
                return ;
            }
            Message msg = Message.obtain(listenerHandler,msg_onUserStatusNotify, status, 0, fromId);
            listenerHandler.sendMessage(msg);
        }
        @Override
        public void onUserDataNotify(String userData, String fromId) {
            if (null == listenerHandler) {
                return ;
            }
            Message msg = obtainMessage(msg_onUserDataNotify, userData, fromId);
            listenerHandler.sendMessage(msg);
        }
    }
    private Message obtainMessage(int what, String userData, String fromId) {
        Message msg = Message.obtain(listenerHandler);
        msg.what = what;
        Bundle data = new Bundle();
        data.putString("userData", userData);
        data.putString("fromId", fromId);
        msg.setData(data);
        return msg;
    }
}
