<?php

use think\Db;
use addons\fastim\library\Common;
use addons\fastim\library\CommonCode;
use addons\fastim\library\controller\Base;
use think\exception\PDOException;

/**
 * im用户相关
 */
class User extends Base
{
    protected $noNeedLogin = [];


    public function pushCid($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['type', 'clientid', 'platform'], $data)) {
            return false;
        }

        if ($data['type'] == 'logout') {
            Db::name('fastim_user_push_clientid')
                ->where('user_id', $this->userInfo['id'])
                ->where('clientid', $data['clientid'])
                ->where('platform', $data['platform'])
                ->delete();

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'logout',
                'data'  => []
            ]));
            return false;
        }

        $userClientValueId = Db::name('fastim_user_push_clientid')
            ->where('user_id', $this->userInfo['id'])
            ->where('clientid', $data['clientid'])
            ->where('platform', $data['platform'])
            ->value('id');
        if ($userClientValueId) {
            Db::name('fastim_user_push_clientid')->where('id', $userClientValueId)->update([
                'updatetime' => time()
            ]);
        } else {
            Db::name('fastim_user_push_clientid')->insert([
                'user_id'    => $this->userInfo['id'],
                'clientid'   => $data['clientid'],
                'platform'   => $data['platform'],
                'updatetime' => time()
            ]);
        }
    }

    /**
     * 标记语音消息已播放(非已读)
     */
    public function changeVoiceStatus($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id'], $data)) {
            return;
        }

        // 只简单确认是否是真实语音的消息即可
        $message = Db::name('fastim_message')
            ->where('id', $data['id'])
            ->where('type', 'voice')
            ->value('id');
        if ($message) {
            Db::name('fastim_reading_log')
                ->insert([
                    'type'       => 1,
                    'user_id'    => $this->userInfo['id'],
                    'data_id'    => $data['id'],
                    'createtime' => time()
                ]);
        }
    }

    public function userShield($data)
    {
        if (!isset($data['page']) || $data['page'] == 1) {
            $min          = 0;
            $data['page'] = 1;
        } else {
            $min = ($data['page'] - 1) * $this->pageCount;
        }

        $shieldUsers = Db::name('fastim_user_shield')
            ->alias('s')
            ->field('s.*,f.remark,fu.nickname as fu_nickname,fu.avatar as fu_avatar,a.nickname as a_nickname,a.avatar as a_avatar,u.nickname,u.avatar,u.id as uid,se.id as session_id')
            ->join('fastim_session se', '(se.user_one=s.user_id AND se.user_two=s.shield_id) OR (se.user_one=s.shield_id AND se.user_two=s.user_id)')
            ->join('fastim_user u', 's.shield_id=u.id')
            ->join('user fu', 'u.user_id=fu.id', 'LEFT')
            ->join('admin a', 'u.admin_id=a.id', 'LEFT')
            ->join('fastim_friendship f', 's.user_id=f.user_id AND s.shield_id=f.friend_id', 'LEFT')
            ->where('s.user_id', $this->userInfo['id'])
            ->limit($min, $this->pageCount)
            ->select();

        foreach ($shieldUsers as $key => $value) {
            $shieldUsers[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                $value['nickname'],
                $value['fu_nickname'],
                $value['a_nickname']
            ], $value['uid']));

            $nickname = Common::trueAttr(Common::nicknameSort([
                $value['remark'],
                $shieldUsers[$key]['nickname']
            ], $value['uid']));

            $shieldUsers[$key]['avatar'] = Common::avatarSrc([
                $value['avatar'],
                $value['fu_avatar'],
                $value['a_avatar']
            ], $nickname);

            unset($shieldUsers[$key]['fu_nickname'], $shieldUsers[$key]['a_nickname'], $shieldUsers[$key]['fu_avatar'], $shieldUsers[$key]['a_avatar']);
        }

        $nextpage = (count($shieldUsers) < $this->pageCount) ? false : true;

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'user-shield',
            'data'  => [
                'data'         => $data,
                'shield_users' => $shieldUsers,
                'nextpage'     => $nextpage
            ]
        ]));
    }

    /**
     * 用户收藏
     * @param  [type] $data [description]
     * @return [type]       [description]
     */
    public function collection($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'action'], $data)) {
            return;
        }

        if ($data['action'] == 'del') {
            if (Db::name('fastim_user_collection')
                ->where('id', $data['id'])
                ->where('user_id', $this->userInfo['id'])
                ->delete()) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'del-collection',
                    'data'  => [
                        'data' => $data,
                        'msg'  => '收藏已删除~'
                    ]
                ]));
            }
        }
    }

    /**
     * 聊天设置
     */
    public function sessionSetting($data)
    {
        $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);
        if ($sessionInfo['user_one'] != $this->userInfo['id'] && $sessionInfo['user_two'] != $this->userInfo['id']) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '您没有权限访问~'
            ]));
            return;
        }

        // 是否置顶
        $sessionInfo['top'] = Db::name('fastim_session_top')
            ->where('user_id', $this->userInfo['id'])
            ->where('session_id', $data['session_id'])
            ->value('top');
        $sessionInfo['top'] = $sessionInfo['top'] ? true : false;

        if ($sessionInfo['type'] == 'single') {
            $friendId = ($sessionInfo['user_one'] == $this->userInfo['id']) ? $sessionInfo['user_two'] : $sessionInfo['user_one'];
            $friend   = Db::name('fastim_friendship')
                ->where('user_id', $this->userInfo['id'])
                ->where('friend_id', $friendId)
                ->find();

            // 是否是好友
            $sessionInfo['friend'] = $friend ? true : false;

            // 是否屏蔽
            $sessionInfo['shield'] = Db::name('fastim_user_shield')
                ->where('user_id', $this->userInfo['id'])
                ->where('shield_id', $friendId)
                ->value('id');
            $sessionInfo['shield'] = $sessionInfo['shield'] ? true : false;

            // 是否是常用联系人
            $sessionInfo['top_contacts'] = ($friend && $friend['top_contacts']) ? true : false;
        } elseif ($sessionInfo['type'] == 'group') {
            $groupUser = Db::name('fastim_group_user')
                ->where('group_id', $sessionInfo['chat_id'])
                ->where('user_id', $this->userInfo['id'])
                ->find();

            // 消息免打扰
            $sessionInfo['block_messages'] = $groupUser['block_messages'] ? true : false;

            // 我的群聊备注
            $sessionInfo['nickname'] = $groupUser['nickname'];

            // 是否是群主
            $sessionInfo['isLeader'] = ($sessionInfo['sessionUser']['leader'] == $this->userInfo['id']) ? true : false;

            // 群公告条数-未读群公告数
            $unreadNoticeNumber = Db::name('fastim_group_chat_notice')
                ->alias('cn')
                ->field('cn.*,r.id AS rid')
                ->join('fastim_reading_log r', 'r.type=0 AND r.user_id=:user_id AND r.data_id=cn.id', 'LEFT')
                ->where('cn.group_id', $sessionInfo['chat_id'])
                ->where('cn.deletetime', null)
                ->where('r.id', null)
                ->bind([
                    'user_id' => $this->userInfo['id']
                ])
                ->count('*');
            if ($unreadNoticeNumber) {
                $sessionInfo['notice'] = $unreadNoticeNumber . '条未读';
            } else {
                $number                = Db::name('fastim_group_chat_notice')
                    ->where('group_id', $sessionInfo['chat_id'])
                    ->where('deletetime', null)
                    ->count('*');
                $sessionInfo['notice'] = $number . '条';
            }
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'session-setting',
            'data'  => [
                'session_info' => $sessionInfo
            ]
        ]));
    }

    /**
     * 获得用户与指定服务号的会话ID
     * @param  [type] $data [description]
     * @return [type]       [description]
     */
    public function getServiceSession($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['service_id'], $data)) {
            return;
        }

        $userImSession = Common::imSession('service', $this->userInfo['id'], $data['service_id']);
        $this->server->push($this->frame->fd, json_encode([
            'event' => 'service_session',
            'data'  => [
                'data'         => $data,
                'service_info' => $userImSession
            ]
        ]));
    }

    /**
     * 删除联系人/群
     */
    public function delContact($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'type'], $data)) {
            return;
        }

        if ($data['type'] == 'user') {
            // 删除好友
            Db::name('fastim_friendship')
                ->where('user_id', $this->userInfo['id'])
                ->where('friend_id', $data['id'])
                ->delete();
            $msg = '好友删除成功~';
        } elseif ($data['type'] == 'group') {
            // 退出群聊
            $groupChat = Common::getImGroupChat($data['id']);
            if ($groupChat['leader'] == $this->userInfo['id']) {

                $groupUser = Db::name('fastim_group_user')->where('group_id', $data['id'])->select();

                Db::startTrans();
                try {
                    Db::name('fastim_session')->where('type', 'group')->where('chat_id', $data['id'])->delete();
                    Db::name('fastim_group_user')->where('group_id', $data['id'])->delete();
                    Db::name('fastim_group_chat')
                        ->where('id', $data['id'])
                        ->where('leader', $this->userInfo['id'])
                        ->update([
                            'deletetime' => time()
                        ]);
                    Db::commit();
                } catch (PDOException $e) {
                    Db::rollback();
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => $e->getMessage()
                    ]));
                    return;
                }

                $notice = [
                    'action' => 'dismiss'
                ];

                // 通知所有群成员重载会话列表
                foreach ($groupUser as $key => $value) {
                    if ($value['user_id'] == $this->userInfo['id']) {
                        $notice['notice'] = '你已经解散了群聊';
                    } else {
                        $notice['notice'] = '群主已经解散了群聊';
                    }

                    // 发送一个群通知给所有群成员
                    $groupImSession = Common::imSession('service', $value['user_id'], 2);
                    $messageData    = Common::insertMessage([
                        'type'         => 'group_notice',
                        'group_id'     => $data['id'],
                        'session_id'   => $groupImSession['id'],
                        'sender_id'    => 0,
                        'recipient_id' => $value['user_id'],
                        'message'      => $notice
                    ]);

                    // 消息无需推送,直接重装会话列表
                    $this->swooleCommon->pushMessageToUser($value['user_id'], [
                        'event' => 'reload_session_list'
                    ]);
                }

                $msg = '已解散群聊~';

            } else {

                $notice = [
                    'action'    => 'quit',
                    'quit_user' => $this->userInfo['id']
                ];

                Db::startTrans();
                try {
                    Db::name('fastim_group_user')
                        ->where('group_id', $data['id'])
                        ->where('user_id', $this->userInfo['id'])
                        ->delete();
                    Db::name('fastim_session')
                        ->where('type', 'group')
                        ->where('user_one', $this->userInfo['id'])
                        ->where('chat_id', $data['id'])
                        ->delete();

                    // 给群主发送一个通知
                    $groupImSession = Common::imSession('service', $groupChat['leader'], 2);
                    $messageData    = Common::insertMessage([
                        'type'         => 'group_notice',
                        'group_id'     => $data['id'],
                        'session_id'   => $groupImSession['id'],
                        'sender_id'    => 0,
                        'recipient_id' => $groupChat['leader'],
                        'message'      => $notice
                    ]);
                    if ($messageData) {
                        $sessionInfo                  = Common::sessionInfo($groupImSession['id'], $groupChat['leader']);
                        $sessionInfo['userInfo']      = Common::getImUserInfo($groupChat['leader']);
                        $sessionInfo['groupChatInfo'] = $groupChat;
                        $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $groupChat['leader']);
                    }

                    Db::commit();
                } catch (PDOException $e) {
                    Db::rollback();
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => $e->getMessage()
                    ]));
                    return false;
                }

                $msg = '已退出群聊~';
            }
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'del-contact',
            'data'  => [
                'data' => $data,
                'msg'  => $msg
            ]
        ]));
    }

    /**
     * 加入群聊
     */
    public function joinGroupOption($data, $directAgree = false)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'action'], $data, false, ['id' => '申请消息找不到啦~'])) {
            return false;
        }
        $message = Db::name('fastim_message')->where('id', $data['id'])->where('type', 'group_apply')->find();
        if (!$message) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '申请消息找不到啦~'
            ]));
            return false;
        }

        if (!$directAgree) {
            $groupChat = Common::getImGroupChat($message['group_id']);
            if (!$groupChat || ($groupChat['leader'] != $this->userInfo['id'])) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您没有权限操作~'
                ]));
                return false;
            }
        }

        $message['message'] = json_decode($message['message'], true);
        if ($data['action'] == 'agree' || $data['action'] == 'autoagree') {
            // 同意入群
            Db::startTrans();
            try {
                $imSession = Common::imSession('group', $message['sender_id'], $message['group_id']);
                $groupUser = [
                    'group_id'      => $message['group_id'],
                    'user_id'       => $message['sender_id'],
                    'session_id'    => $imSession['id'],
                    'user_group_id' => (int)$message['message']['group'],
                    'jointime'      => time()
                ];
                Db::name('fastim_group_user')->insert($groupUser);

                // 推送群消息
                $this->swooleCommon->pushMessageToGroup('system', [
                    'group_id'     => $message['group_id'],
                    'session_id'   => $imSession['id'],
                    'sender_id'    => $this->userInfo['id'],
                    'recipient_id' => $message['sender_id'],
                    'message'      => [
                        'message'      => '你已经是群成员了，和大家打个招呼吧~',
                        'display_user' => $message['sender_id']
                    ]
                ]);

                Db::commit();
            } catch (PDOException $e) {
                Db::rollback();
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => $e->getMessage()
                ]));
                return false;
            }

            if ($data['action'] == 'agree') {
                $res = [
                    'msg'        => '已同意加群申请~',
                    'type'       => 'success',
                    'session_id' => $message['session_id']
                ];
            }
        } else {
            $res = [
                'msg'        => '已拒绝加群申请~',
                'type'       => 'tips',
                'session_id' => $message['session_id']
            ];

            // 给被拒绝用户推送消息
            $imSession                    = Common::imSession('service', $message['sender_id'], 2);
            $sessionInfo                  = Common::sessionInfo($imSession['id'], $message['sender_id']);
            $messageData                  = Common::insertMessage([
                'type'         => 'group_notice',
                'group_id'     => $message['group_id'],
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => $this->userInfo['id'],
                'recipient_id' => $message['sender_id'],
                'message'      => [
                    'action'      => 'refuse',
                    'refuse_user' => $message['sender_id']
                ]
            ]);
            $sessionInfo['userInfo']      = Common::getImUserInfo($message['sender_id'], false, $message['sender_id']);
            $sessionInfo['groupChatInfo'] = Common::getImGroupChat($message['group_id']);
            $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $message['sender_id']);
        }

        // 同类申请
        $applyMessage = Db::name('fastim_message')
            ->where('group_id', $message['group_id'])
            ->where('type', 'group_apply')
            ->where('sender_id', $message['sender_id'])
            ->where('recipient_id', $message['recipient_id'])
            ->select();

        foreach ($applyMessage as $key => $value) {
            $msg = json_decode($value['message'], true);
            if (!isset($msg['result']) || !$msg['result'] || $msg['result'] == 'pending') {
                $msg['result'] = $data['action'];
                $msg           = json_encode($msg);
                Db::name('fastim_message')->where('id', $value['id'])->update(['message' => $msg]);
            }
        }

        if (isset($res)) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'new_friends_option',
                'data'  => $res
            ]));
        }
        return true;
    }

    /**
     * 新朋友申请消息处理
     */
    public function newFriendsOption($data, $agreeUserId = 0)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'action'], $data, false, ['id' => '好友申请消息找不到啦~'])) {
            return;
        }

        $message = Db::name('fastim_message')->where('id', $data['id'])->where('type', 'friend_apply')->find();

        if (!$message) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '好友申请消息找不到啦~'
            ]));
            return;
        }
        $message['message'] = json_decode($message['message'], true);

        $uid           = $agreeUserId ? $agreeUserId : $this->userInfo['id'];
        $userImSession = Common::imSession('service', $uid, 1);

        if ($data['action'] == 'agree' || $data['action'] == 'autoagree') {
            // 同意-插入两条好友记录
            $friendship = Db::name('fastim_friendship')
                ->where('user_id', $uid)
                ->where('friend_id', $message['sender_id'])
                ->value('user_id');
            if (!$friendship) {
                $friend[] = [
                    'user_id'    => $uid,
                    'friend_id'  => $message['sender_id'],
                    'group'      => isset($data['data']['new_contact_user_group']) ? (int)$data['data']['new_contact_user_group'] : 0,
                    'remark'     => $data['data']['new_contact_remark'] ?? '',
                    'createtime' => time()
                ];
            }

            $friendship = Db::name('fastim_friendship')
                ->where('user_id', $message['sender_id'])
                ->where('friend_id', $uid)
                ->value('friend_id');
            if (!$friendship) {
                $friend[] = [
                    'user_id'    => $message['sender_id'],
                    'friend_id'  => $uid,
                    'group'      => isset($message['message']['group']) ? (int)$message['message']['group'] : 0,
                    'remark'     => $message['message']['remark'] ?? '',
                    'createtime' => time()
                ];
            }

            if (isset($friend) && $friend) {
                Db::name('fastim_friendship')->insertAll($friend);
            } else {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '你们已经是好友了哦~'
                ]));
                return;
            }

            // 给双方发送通知消息
            $imSession = Common::imSession('single', $uid, $message['sender_id']);

            $sessionInfo[] = Common::sessionInfo($imSession['id'], $message['sender_id']);
            $sessionInfo[] = Common::sessionInfo($imSession['id'], $uid);

            foreach ($sessionInfo as $key => $value) {
                // 消息入库
                $messageData = Common::insertMessage([
                    'type'         => 'system',
                    'session_id'   => $value['id'],
                    'sender_id'    => $value['user']['id'],
                    'recipient_id' => $value['sessionUser']['id'],
                    'message'      => [
                        'message'      => '我们已经是好友了~',
                        'display_user' => $value['sessionUser']['id']
                    ]
                ]);
                if ($messageData) {
                    $value['pushUser'] = Common::getImUserInfo($value['user']['id'], false, $value['sessionUser']['id']);
                    $this->swooleCommon->newMessagePush($messageData, $value, $value['sessionUser']['id']);
                }
            }

            if ($data['action'] == 'agree') {
                $res = [
                    'msg'        => '已同意好友申请~',
                    'type'       => 'success',
                    'session_id' => $message['session_id']
                ];
            }

        } elseif ($data['action'] == 'refuse') {

            $res = [
                'msg'        => '已拒绝好友申请~',
                'type'       => 'tips',
                'session_id' => $userImSession['id']
            ];

            // 给被拒绝的用户推送消息
            $imSession               = Common::imSession('service', $message['sender_id'], 1);
            $sessionInfo             = Common::sessionInfo($imSession['id'], $message['sender_id']);
            $messageData             = Common::insertMessage([
                'type'         => 'friend_apply',
                'session_id'   => $sessionInfo['id'],
                'sender_id'    => $uid,
                'recipient_id' => $message['sender_id'],
                'message'      => [
                    'method' => 'notice',
                    'result' => 'refuse'
                ]
            ]);
            $sessionInfo['userInfo'] = Common::getImUserInfo($uid, false, $message['sender_id']);
            $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $message['sender_id']);
        }

        // 同类申请消息
        $similarMessage = Db::name('fastim_message')
            ->where('type', 'friend_apply')
            ->where('sender_id', $message['sender_id'])
            ->where('recipient_id', $message['recipient_id'])
            ->select();

        // 对所有同类申进行标记
        foreach ($similarMessage as $key => $value) {
            $msg = json_decode($value['message'], true);
            if ($msg['method'] == 'apply' && (!isset($msg['result']) || !$msg['result'] || $msg['result'] == 'pending')) {
                $msg['result'] = $data['action'];
                $msg           = json_encode($msg);
                Db::name('fastim_message')->where('id', $value['id'])->update(['message' => $msg]);
            }
        }

        if (isset($res)) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'new_friends_option',
                'data'  => $res
            ]));
        }
    }

    /**
     * 申请添加新联系人/群
     */
    public function createNewContact($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'type', 'method', 'action'], $data)) {
            return false;
        }

        if ($data['type'] == 'friends') {
            // 查得被添加用户基本信息
            $info = Common::getImUserInfo($data['id']);
            if ($info['id'] == $this->userInfo['id']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '无需添加自己为好友~'
                ]));
                return false;
            }

            $friendship = Db::name('fastim_friendship')
                ->where('user_id', $this->userInfo['id'])
                ->where('friend_id', $info['id'])
                ->find();

            if ($data['action'] == 'pre-agree' && isset($data['message_id'])) {
                // 查得消息资料
                $info['message'] = Db::name('fastim_message')
                    ->where('id', $data['message_id'])
                    ->where('type', 'friend_apply')
                    ->find();
                if ($info['message']) {
                    $info['message']['message'] = json_decode($info['message']['message'], true);
                    $info['add_note']           = isset($info['message']['message']['note']) ? $info['message']['message']['note'] : '';
                    unset($info['message']);
                }
            }

            if ($friendship) {
                if ($data['action'] == 'pre-agree') {
                    // 预同意申请请求，直接同意
                    $this->newFriendsOption(['id' => $data['message_id'], 'action' => 'agree'], $this->userInfo['id']);
                    return false;
                } else {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => 'TA已经是您的好友了哦~'
                    ]));
                    return false;
                }
            }

            // 查得用户的分组设置
            $group = Common::getGroups($this->userInfo['id'], 0);
            array_splice($group, 0, 1);// 删除常用联系人分组

            // 用户验证要求配置
            $imUserConfig          = Common::imUserConfig($info['id']);
            $info['verify_method'] = $imUserConfig['verify_method'];
            $info['temp_session']  = $imUserConfig['temp_session'];

            if ($data['method'] == 'post') {
                // 获得被添加用户与“新朋友”服务号的会话
                $imSession = Common::imSession('service', $data['id'], 1);
                if (!$imSession) {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => '申请发送失败,请稍后重试~'
                    ]));
                    return false;
                }
                // 发送好友申请
                $message     = [
                    'remark' => $data['new_contact_remark'],
                    'group'  => isset($data['new_contact_user_group']) ? (int)$data['new_contact_user_group'] : 0,
                    'note'   => $data['new_contact_note'] ?? '',
                    'source' => '搜索好友',
                    'result' => 'pending',
                    'method' => 'apply'
                ];
                $sessionInfo = Common::sessionInfo($imSession['id'], $this->userInfo['id']);

                // 消息入库
                $messageData = Common::insertMessage([
                    'type'         => 'friend_apply',
                    'session_id'   => $sessionInfo['id'],
                    'sender_id'    => $this->userInfo['id'],
                    'recipient_id' => $data['id'],
                    'message'      => $message
                ]);

                if ($messageData) {
                    // 推送申请消息给被添加人
                    $sessionInfo['pushUser'] = $sessionInfo['sessionUser'];
                    $sessionInfo['userInfo'] = $sessionInfo['user'];
                    $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $data['id']);

                    // 如果被添加人无需验证-直接同意
                    if ($info['verify_method'] == 1) {
                        $this->newFriendsOption(['id' => $messageData['id'], 'action' => 'autoagree'], $info['id']);
                        $res = [
                            'msg'  => '成功添加好友~',
                            'type' => 'success'
                        ];
                    } else {
                        $imSession               = Common::imSession('service', $this->userInfo['id'], 1);
                        $sessionInfo             = Common::sessionInfo($imSession['id'], $this->userInfo['id']);
                        $sessionInfo['userInfo'] = $info;
                        $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $this->userInfo['id']);
                        $res = [
                            'msg'  => '好友申请已发送~',
                            'type' => 'success'
                        ];
                    }

                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => $res
                    ]));
                } else {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => '申请发送失败,请稍后重试~'
                    ]));
                }
                return false;
            }

        } elseif ($data['type'] == 'group') {
            // 查得被添加群聊基本信息
            $info = Common::getImGroupChat($data['id']);

            if (!$info) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '你查找的群聊找不到啦~'
                ]));
                return false;
            }

            $groupMember = Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $this->userInfo['id'])
                ->value('group_id');

            if ($groupMember) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您已经是群聊成员了~'
                ]));
                return false;
            }

            // 查得用户的分组设置
            $group = Common::getGroups($this->userInfo['id'], 1);
            unset($info['invite_join_group']);

            if ($data['method'] == 'post') {
                // 建立群主和“群通知”的会话
                $imSessionLeader = $info['leader'] ? Common::imSession('service', $info['leader'], 2) : false;
                if (!$imSessionLeader) {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => '申请发送失败,请稍后重试~'
                    ]));
                    return false;
                }

                // 发送加群申请-申请人为发送人，群主为接受人
                $message     = [
                    'group'  => isset($data['new_contact_user_group']) ? (int)$data['new_contact_user_group'] : 0,
                    'note'   => $data['new_contact_note'] ?? '',
                    'source' => '搜索群聊',
                    'result' => 'pending'
                ];
                $sessionInfo = Common::sessionInfo($imSessionLeader['id'], $this->userInfo['id']);

                // 消息入库
                $messageData = Common::insertMessage([
                    'type'         => 'group_apply',
                    'session_id'   => $imSessionLeader['id'],
                    'sender_id'    => $this->userInfo['id'],
                    'recipient_id' => $info['leader'],
                    'message'      => $message,
                    'group_id'     => $data['id']
                ]);

                if ($messageData) {
                    $sessionInfo['userInfo']      = Common::getImUserInfo($this->userInfo['id']);
                    $sessionInfo['groupChatInfo'] = $info;
                    $this->swooleCommon->newMessagePush($messageData, $sessionInfo, $info['leader']);
                    if ($info['add_mode'] == 1) {
                        // 无需验证-直接入群
                        if ($this->joinGroupOption(['id' => $messageData['id'], 'action' => 'autoagree'], true)) {
                            $res = [
                                'msg'  => '成功加入群聊~',
                                'type' => 'success'
                            ];
                        } else {
                            $res = [
                                'msg'  => '加群失败，请重试~',
                                'type' => 'error'
                            ];
                        }
                    } else {
                        // 建立加群人和“群通知”的会话
                        Common::imSession('service', $this->userInfo['id'], 2);
                        $this->server->push($this->frame->fd, json_encode([
                            'event' => 'reload_session_list'
                        ]));
                        $res = [
                            'msg'  => '加群申请已发送~',
                            'type' => 'success'
                        ];
                    }
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => $res
                    ]));
                } else {
                    $this->server->push($this->frame->fd, json_encode([
                        'event' => 'show_msg',
                        'data'  => '申请发送失败,请稍后重试~'
                    ]));
                }
                return false;
            }

        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'create_new_contact',
            'data'  => [
                'info'  => $info,
                'data'  => $data,
                'group' => $group
            ]
        ]));
    }

    /**
     * 屏蔽一个会话
     */
    public function shieldSession($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['session_id', 'method'], $data)) {
            return;
        }

        $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);

        $exist = Db::name('fastim_user_shield')
            ->where('user_id', $this->userInfo['id'])
            ->where('shield_id', $sessionInfo['sessionUser']['id'])
            ->value('id');

        if ($data['method'] == 'shield' && !$exist) {
            $shield = [
                'user_id'   => $this->userInfo['id'],
                'shield_id' => $sessionInfo['sessionUser']['id']
            ];
            Db::name('fastim_user_shield')->insert($shield);
            if ($sessionInfo['deleteuser']) {
                Db::name('fastim_session')->where('id', $sessionInfo['id'])->delete();
            } else {
                Db::name('fastim_session')->where('id', $sessionInfo['id'])->update([
                    'deleteuser' => $this->userInfo['id']
                ]);
            }
        } elseif ($data['method'] == 'relieve' && $exist) {
            Db::name('fastim_user_shield')->where('id', $exist)->delete();
            if ($sessionInfo['deleteuser'] == $this->userInfo['id']) {
                Db::name('fastim_session')->where('id', $sessionInfo['id'])->update([
                    'deleteuser' => 0
                ]);
            }
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'shield_session',
            'data'  => [
                'session_id' => $data['session_id'],
                'method'     => $data['method']
            ]
        ]));
    }

    /**
     * 更新好友备注/分组等
     */
    public function updateFriendInfo($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'method'], $data)) {
            return;
        }

        if ($data['method'] == 'update_remark') {
            if (!$this->swooleCommon->requiredParamCheck(['new_remark'], $data, false, ['new_remark' => '请输入正确的好友备注~'])) {
                return;
            }

            Db::name('fastim_friendship')
                ->where('user_id', $this->userInfo['id'])
                ->where('friend_id', $data['id'])
                ->update([
                    'remark' => $data['new_remark']
                ]);

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '好友备注修改成功~',
                    'type' => 'success'
                ]
            ]));

            $this->infoDetail([
                'id'     => $data['id'],
                'method' => 'get-new-info',
                'type'   => 'user'
            ]);
        } elseif ($data['method'] == 'update_group') {
            $update = true;
            if ($data['new_group'] == 'common') {
                Db::name('fastim_friendship')
                    ->where('user_id', $this->userInfo['id'])
                    ->where('friend_id', $data['id'])
                    ->update([
                        'top_contacts' => 1
                    ]);
                $update = false;
            } elseif ($data['new_group'] == 'all_friends') {
                $data['new_group'] = 0;
            }

            if ($update) {
                Db::name('fastim_friendship')
                    ->where('user_id', $this->userInfo['id'])
                    ->where('friend_id', $data['id'])
                    ->update([
                        'group'        => (int)$data['new_group'],
                        'top_contacts' => 0
                    ]);
            }
            if (isset($data['source']) && $data['source'] == 'uni-app') {
                $msg = ($data['new_group'] === 'common') ? '已添加好友至常用联系人~' : '已取消常用联系人~';
            } else {
                $msg = '好友分组修改成功~';
            }

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => $msg,
                    'type' => 'success'
                ]
            ]));
        } elseif ($data['method'] == 'update_groupchat_group') {
            if ($data['new_group'] == 'all_group') {
                $data['new_group'] = 0;
            }

            Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $this->userInfo['id'])
                ->update([
                    'user_group_id' => (int)$data['new_group']
                ]);

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '群聊分组修改成功~',
                    'type' => 'success'
                ]
            ]));
        }
    }

    /**
     * 用户和群聊资料
     */
    public function infoDetail($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'type', 'method'], $data)) {
            return false;
        }

        if ($data['type'] == 'user') {
            $info = Common::getImUserInfo($data['id'], true, $this->userInfo['id']);
        } elseif ($data['type'] == 'group') {
            $info = Common::getImGroupChat($data['id']);
        } elseif ($data['type'] == 'service') {
            $info = Db::name('fastim_service')->where('id', $data['id'])->find();
        }

        if (!$info) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '获取资料失败,请重试~'
            ]));
            return false;
        }

        if ($data['type'] == 'user') {
            $info['occupation'] = ($data['method'] == 'user-edit') ? $info['occupation'] : Common::formatOccupation($info['occupation']);

            // 取得用户好友分组
            $info['groups'] = Common::getGroups($this->userInfo['id'], 0);
        } elseif ($data['type'] == 'group') {
            $info['createtime'] = Common::formatTime($info['createtime']);
            $info['leader']     = Common::getImUserInfo($info['leader'], true, $this->userInfo['id']);
            $info['isLeader']   = true;
            if (!$info['leader'] || ($info['leader']['id'] != $this->userInfo['id'])) {
                // 不是leader,去除群的隐私资料
                $info['isLeader'] = false;
                unset($info['add_mode'], $info['invite_join_group'], $info['history_message'], $info['retrieval_settings']);
            }

            $groupUser = Db::name('fastim_group_user')
                ->where('group_id', $data['id'])
                ->where('user_id', $this->userInfo['id'])
                ->find();

            if ($groupUser) {
                $info['groupMember'] = $groupUser['group_id'];
                $info['group']       = $groupUser['user_group_id'] ? $groupUser['user_group_id'] : 'all_group';
            } else {
                $info['groupMember'] = false;
                $info['group']       = 'all_group';
            }

            // 取得用户群聊分组
            $info['groups'] = Common::getGroups($this->userInfo['id'], 1);
        } elseif ($data['type'] == 'service') {
            $info['avatar'] = Common::avatarSrc([
                $info['avatar']
            ], $info['nickname']);
        }

        if ($data['method'] == 'user-edit') {
            // 编辑用户资料
            if ($data['id'] != $this->userInfo['id']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您没有权限操作~'
                ]));
                return false;
            }
            $info['birthday']       = $info['birthday'] ? explode('-', $info['birthday']) : false;
            $info['occupationData'] = Common::formatOccupation(false);
        } elseif ($data['method'] == 'group-edit') {
            // 编辑群资料
            if (!$info['isLeader']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您没有权限操作~'
                ]));
                return false;
            }
        } elseif ($data['method'] == 'post-user-edit' && $data['id'] == $this->userInfo['id']) {
            // 保存用户资料
            unset($data['method'], $data['type']);

            if (!$this->swooleCommon->requiredParamCheck(['nickname'], $data, false, ['nickname' => '请输入正确的昵称~'])) {
                return false;
            }

            $data['birthday'] = (isset($data['birthday']) && $data['birthday']) ? $data['birthday'] : date('Y-m-d');
            Db::name('fastim_user')->where('id', $this->userInfo['id'])->update($data);
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '资料保存成功~',
                    'type' => 'success'
                ]
            ]));
            return false;
        } elseif ($data['method'] == 'post-group-edit') {
            if (!$info['isLeader']) {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'show_msg',
                    'data'  => '您没有权限操作~'
                ]));
                return false;
            }

            if (!$this->swooleCommon->requiredParamCheck(['nickname'], $data, false, ['nickname' => '请输入正确的群名称~'])) {
                return false;
            }
            // 保存群聊资料
            unset($data['method'], $data['type'], $data['action']);
            Db::name('fastim_group_chat')->update($data);
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => [
                    'msg'  => '资料保存成功~',
                    'type' => 'success'
                ]
            ]));
            return false;
        } elseif ($data['method'] == 'post-avatar') {
            // 修改头像
            if ($data['type'] == 'user') {
                Db::name('fastim_user')->where('id', $this->userInfo['id'])->update([
                    'avatar' => $data['url']
                ]);
            } elseif ($data['type'] == 'group' && $info['isLeader']) {
                Db::name('fastim_group_chat')->where('id', $info['id'])->update([
                    'avatar' => $data['url']
                ]);
            }
            $info['avatar'] = $data['url'];
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'info-detail',
            'data'  => [
                'info' => $info,
                'data' => $data
            ]
        ]));
    }

    /**
     * 加载会话
     */
    public function loadSession($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['session_id'], $data, false, ['session_id' => '会话找不到啦~'])) {
            return;
        }

        // 获取会话资料
        $sessionInfo = Common::sessionInfo($data['session_id'], $this->userInfo['id']);
        if (!$sessionInfo) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '会话找不到啦~'
            ]));
            return;
        }
        // 置顶状态
        $sessionInfo['top'] = Db::name('fastim_session_top')
            ->where('user_id', $this->userInfo['id'])
            ->where('session_id', $sessionInfo['id'])
            ->value('top');

        // 是否为已绑定用户的游客
        $tourist        = $this->swooleCommon->getUserIsTourist($this->frame->fd);
        $imUserBindUser = Db::name('fastim_user')
            ->field('user_id, admin_id')
            ->where('id', $this->userInfo['id'])
            ->find();
        if (($tourist == 1) && $imUserBindUser && ($imUserBindUser['admin_id'] || $imUserBindUser['user_id'])) {
            $sessionInfo['windowType'] = 'fake_tourist';
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'load_session',
                'data'  => [
                    'info'  => $sessionInfo,
                    'admin' => $imUserBindUser['admin_id']
                ]
            ]));
            return;
        }

        if (!isset($data['page']) || $data['page'] == 1) {
            $min          = 0;
            $data['page'] = 1;
        } else {
            $min = ($data['page'] - 1) * $this->pageCount;
        }

        if ($sessionInfo['type'] == 'single') {
            // 单聊消息

            // 标记已读
            Db::name('fastim_message')
                ->where('session_id', $data['session_id'])
                ->where('recipient_id', $this->userInfo['id'])
                ->where('status', 0)
                ->update(['status' => 1]);

            // 发送已读通知
            $this->swooleCommon->pushMessageToUser($sessionInfo['sessionUser']['id'], [
                'event' => 'read_message',
                'data'  => [
                    'sessionType' => 0,
                    'session_id'  => $data['session_id']
                ]
            ]);

            $message = Common::loadSingleChatRecord($data['session_id'], [
                'min'       => $min,
                'pageCount' => $this->pageCount
            ], $this->userInfo['id']);

            $nextpage = (count($message) < $this->pageCount) ? false : true;

            if ($data['page'] == 1) {
                $message = array_reverse($message, false);
                $message = Common::groupByTime($message, 'desc');
            } else {
                $message = Common::groupByTime($message);
            }

            $sessionInfo['shield'] = Db::name('fastim_user_shield')
                ->where('user_id', $this->userInfo['id'])
                ->where('shield_id', $sessionInfo['sessionUser']['id'])
                ->value('id');

            $sessionInfo['windowType'] = 'message';
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'load_session',
                'data'  => [
                    'message'  => $message,
                    'info'     => $sessionInfo,
                    'nextpage' => $nextpage,
                    'data'     => $data
                ]
            ]));
        } elseif ($sessionInfo['type'] == 'group') {
            // 群聊消息
            // 取得未读公告
            $unreadFixedMsg = Db::name('fastim_group_chat_notice')
                ->alias('cn')
                ->field('cn.*,r.id AS rid')
                ->join('fastim_reading_log r', 'r.type=0 AND r.user_id=:user_id AND r.data_id=cn.id', 'LEFT')
                ->where('cn.group_id', $sessionInfo['chat_id'])
                ->where('cn.popup', 1)
                ->where('cn.deletetime', null)
                ->where('r.id', null)
                ->bind([
                    'user_id' => $this->userInfo['id']
                ])
                ->order('createtime desc')
                ->find();
            $unreadFixedMsg = Common::formatGroupChatNotice($unreadFixedMsg, $this->userInfo['id'], false);

            $this->swooleCommon->readGroupMessage($sessionInfo);

            $message = Common::loadGroupChatRecord($sessionInfo, [
                'min'       => $min,
                'pageCount' => $this->pageCount
            ], $this->userInfo['id']);

            $nextpage = (count($message) < $this->pageCount) ? false : true;

            if ($data['page'] == 1) {
                $message = array_reverse($message, false);
                $message = Common::groupByTime($message, 'desc');
            } else {
                $message = Common::groupByTime($message);
            }

            $sessionInfo['windowType']           = 'message';
            $sessionInfo['sessionUser']['speak'] = ($sessionInfo['sessionUser']['speak'] == 1 && $sessionInfo['sessionUser']['leader'] == $this->userInfo['id']) ? 0 : $sessionInfo['sessionUser']['speak'];
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'load_session',
                'data'  => [
                    'message'        => $message,
                    'info'           => $sessionInfo,
                    'nextpage'       => $nextpage,
                    'data'           => $data,
                    'lastMessage'    => Common::getLastMessage($this->userInfo['id'], $sessionInfo),
                    'unreadFixedMsg' => $unreadFixedMsg
                ]
            ]));
        } elseif ($sessionInfo['type'] == 'service') {
            // 服务号

            // 群通知或好友申请消息
            if ($sessionInfo['chat_id'] == 1 || $sessionInfo['chat_id'] == 2 || $sessionInfo['chat_id'] == 3) {

                Common::readServiceMessage($sessionInfo['chat_id'], $this->userInfo['id'], $sessionInfo['id']);

                $message = Common::loadServiceRecord($sessionInfo, [
                    'min'       => $min,
                    'pageCount' => $this->pageCount
                ], $this->userInfo['id']);
                if ($message) {
                    $sessionInfo['windowType'] = $message['windowType'];
                    $message                   = $message['message'];
                }

                $nextpage = (count($message) < $this->pageCount) ? false : true;

                if ($data['page'] == 1 && $sessionInfo['chat_id'] == 3) {
                    $message = array_reverse($message, false);
                    $message = Common::groupByTime($message, 'desc');
                } else {
                    $message = Common::groupByTime($message);
                }
            }

            $this->server->push($this->frame->fd, json_encode([
                'event' => 'load_session',
                'data'  => [
                    'message'     => $message,
                    'info'        => $sessionInfo,
                    'nextpage'    => $nextpage,
                    'data'        => $data,
                    'lastMessage' => Common::getLastMessage($this->userInfo['id'], $sessionInfo)
                ]
            ]));
        }
    }

    /**
     * 会话列表
     */
    public function loadSessionList($data)
    {
        $data['method'] = $data['method'] ?? 'load';
        if ($data['method'] == 'pickuser') {
            $where['s.type'] = 'single';
        }
        $where['s.deleteuser'] = ['<>', $this->userInfo['id']];

        /**
         * 会话列表
         * 直接关联到了服务号和群聊表的资料、单聊资料需单独获取
         * 通过 message 表的 createtime 排序、会话创建时间辅助排序
         * 涉及群组在会话列表的排序，所以显得复杂，请不要随意改动
         */
        $dbprefix        = config('database.prefix');
        $typeSql         = CommonCode::nonPrivilegedMessage(true);
        $serviceTypeSql  = "IN ('group_invitation', 'group_notice', 'group_apply')";
        $groupMessageExp = "m.type {$typeSql} OR (m.type='system' AND (m.recipient_id=:user_id OR (m.recipient_id=0 AND m.createtime>=gu.jointime)))";
        $orderSubSelect  = "(SELECT createtime FROM `{$dbprefix}fastim_message` `m` WHERE (s.type='single' AND m.session_id=s.id) OR (s.type='service' AND (m.sender_id=:user_id OR m.recipient_id=:user_id) AND ((s.chat_id=1 AND m.type='friend_apply') OR (s.chat_id=2 AND m.type {$serviceTypeSql})) OR (s.chat_id=3)) OR (s.type='group' AND s.chat_id=m.group_id AND ((gc.history_message=0 AND {$groupMessageExp} AND m.createtime>=gu.jointime) OR (gc.history_message=1 AND {$groupMessageExp}))) ORDER BY m.createtime DESC LIMIT 1)";

        $session = Db::name('fastim_session')
            ->alias('s')
            ->field('s.*, se.avatar as se_avatar, se.nickname as se_nickname, se.bio as se_bio, gc.avatar as gc_avatar, gc.nickname as gc_nickname, gc.bio as gc_bio, gc.history_message as gc_history_message, gu.jointime,' . $orderSubSelect . ' as m_createtime, t.top')
            ->join('fastim_group_chat gc', 's.chat_id=gc.id AND s.type="group" AND gc.deletetime IS NULL', 'LEFT')
            ->join('fastim_service se', 's.chat_id=se.id AND s.type="service"', 'LEFT')
            ->join('fastim_group_user gu', 'gu.group_id=gc.id AND gu.user_id=:user_id', 'LEFT')
            ->join('fastim_session_top t', 't.user_id=:user_id AND t.session_id=s.id', 'LEFT') // 会话置顶表
            ->where('s.user_one|s.user_two', $this->userInfo['id'])
            ->where($where)
            ->bind([
                'user_id' => $this->userInfo['id']
            ])
            ->order('t.top desc, m_createtime desc, s.createtime desc')
            ->limit(40)
            ->select(false);
        $session = Db::query($session);

        // 删除这些key以保持干净
        $delKey = [
            'se_avatar'   => '',
            'se_nickname' => '',
            'se_bio'      => '',
            'gc_avatar'   => '',
            'gc_nickname' => '',
            'gc_bio'      => ''
        ];

        // pushUser=会话对象

        foreach ($session as $key => $value) {
            if ($value['type'] == 'single') {
                // 单聊
                $userInfo                        = Common::getImUserInfo(($value['user_one'] == $this->userInfo['id']) ? $value['user_two'] : $value['user_one'], false, $this->userInfo['id']);
                $session[$key]['pushUser']       = $userInfo;
                $session[$key]['searchContinue'] = $userInfo['friend'] ? true : false;
            } elseif ($value['type'] == 'group') {
                // 群聊
                $session[$key]['searchContinue']       = true;
                $session[$key]['pushUser']['nickname'] = $value['gc_nickname'];
                $session[$key]['pushUser']['avatar']   = Common::avatarSrc([
                    $value['gc_avatar']
                ], $session[$key]['pushUser']['nickname']);

                $session[$key]['pushUser']['id']              = $value['chat_id'];
                $session[$key]['pushUser']['bio']             = $value['gc_bio'];
                $session[$key]['pushUser']['history_message'] = $value['gc_history_message'];
                $session[$key]['shield']                      = Common::getGroupChatShield($value['chat_id'], $this->userInfo['id']);
            } elseif ($value['type'] == 'service') {
                // 服务号
                $session[$key]['searchContinue']       = false;
                $session[$key]['pushUser']['nickname'] = $value['se_nickname'];
                $session[$key]['pushUser']['avatar']   = Common::avatarSrc([
                    $value['se_avatar']
                ], $session[$key]['pushUser']['nickname']);

                $session[$key]['pushUser']['id']  = $value['chat_id'];
                $session[$key]['pushUser']['bio'] = $value['se_bio'];
            }

            if (isset($data['keyword'])) {
                if (mb_strpos($session[$key]['pushUser']['nickname'], $data['keyword']) === false || ($session[$key]['searchContinue'])) {
                    unset($session[$key]);
                    continue;
                }
            }

            $session[$key] = array_diff_key($session[$key], $delKey);

            $session[$key] = [
                'sessionInfo'          => $session[$key],
                'lastMessage'          => Common::getLastMessage($this->userInfo['id'], $session[$key]),
                'unreadMessagesNumber' => Common::getUnreadMessagesNumber($this->userInfo['id'], $session[$key])
            ];
        }

        // 搜索来的,不直接返回给前台
        if (isset($data['keyword'])) {
            return $session;
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'load_session_list',
            'data'  => [
                'session' => $session,
                'data'    => $data
            ]
        ]));
    }

    /**
     * 会话右击
     */
    public function sessionOperation($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'action'], $data)) {
            return false;
        }

        $sessionInfo = Db::name('fastim_session')
            ->where('id', $data['id'])
            ->where('user_one|user_two', $this->userInfo['id'])
            ->find();
        if (!$sessionInfo) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '会话找不到啦~'
            ]));
            return false;
        }

        if ($data['action'] == 'session-top') {
            // 置顶会话
            $exist = Db::name('fastim_session_top')
                ->where('user_id', $this->userInfo['id'])
                ->where('session_id', $data['id'])
                ->value('top');
            if ($exist) {
                // 取消置顶
                Db::name('fastim_session_top')
                    ->where('user_id', $this->userInfo['id'])
                    ->where('session_id', $data['id'])
                    ->delete();
            } else {
                // 插入置顶
                /*$maxTop = Db::name('fastim_session_top')
                ->where('user_id', $this->userInfo['id'])
                ->max('top');*/
                Db::name('fastim_session_top')->insert([
                    'user_id'    => $this->userInfo['id'],
                    'session_id' => $data['id'],
                    'top'        => 1
                ]);
            }
            if (!isset($data['source']) || $data['source'] != 'uni-app') {
                $this->loadSessionList([]);
            } else {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'session-operation-tips',
                    'data'  => [
                        'type' => 'success',
                        'msg'  => '会话已' . ($exist ? '取消' : '') . '置顶~'
                    ]
                ]));
            }
        } elseif ($data['action'] == 'session-info') {
            // 会话资料
            if ($sessionInfo['type'] == 'single' || $sessionInfo['type'] == 'group') {
                $info = [
                    'id'   => ($sessionInfo['type'] == 'single') ? ($sessionInfo['user_one'] == $this->userInfo['id']) ? $sessionInfo['user_two'] : $sessionInfo['user_one'] : $sessionInfo['chat_id'],
                    'type' => ($sessionInfo['type'] == 'single') ? 'user' : 'group'
                ];
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'session_info',
                    'data'  => $info
                ]));
                return false;
            }
        } elseif ($data['action'] == 'session-remove') {
            // 移除会话
            Db::name('fastim_session')->where('id', $data['id'])->update([
                'deleteuser' => $this->userInfo['id']
            ]);
            if (!isset($data['source']) || $data['source'] != 'uni-app') {
                $this->loadSessionList([]);
            } else {
                $this->server->push($this->frame->fd, json_encode([
                    'event' => 'session-operation-tips',
                    'data'  => [
                        'type' => 'success',
                        'msg'  => '会话已移除~'
                    ]
                ]));
            }
        } elseif ($data['action'] == 'session-block-groupmessage') {
            // 屏蔽群消息
            $blockMessages = Db::name('fastim_group_user')
                ->where('group_id', $sessionInfo['chat_id'])
                ->where('user_id', $this->userInfo['id'])
                ->value('block_messages');
            Db::name('fastim_group_user')
                ->where('group_id', $sessionInfo['chat_id'])
                ->where('user_id', $this->userInfo['id'])
                ->update([
                    'block_messages' => $blockMessages ? '0' : '1'
                ]);

            $this->server->push($this->frame->fd, json_encode([
                'event' => (!isset($data['source']) || $data['source'] != 'uni-app') ? 'show_msg' : 'session-operation-tips',
                'data'  => [
                    'type' => 'success',
                    'msg'  => '群消息已' . ($blockMessages ? '解除' : '设置为') . '免打扰~'
                ]
            ]));
        }
    }

    /**
     * 搜索用户
     */
    public function search($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['keyword', 'method'], $data, false, ['keyword' => '请输入关键词~'])) {
            return;
        }

        $method = explode('|', $data['method']);// 要搜索的数据类型

        // 搜索好友
        if (in_array('friends', $method)) {
            $friendSql = Db::name('fastim_friendship')
                ->alias('f')
                ->field('f.*,u.avatar,u.nickname,u.status,u.bio,u.gender,fu.avatar as fu_avatar,fu.nickname as fu_nickname,a.avatar as a_avatar,a.nickname as a_nickname,g.name as groupname')
                ->join('fastim_user u', 'f.friend_id=u.id')
                ->join('user fu', 'u.user_id=fu.id', 'LEFT')
                ->join('admin a', 'u.admin_id=a.id', 'LEFT')
                ->join('fastim_group g', 'g.id=f.group AND g.type=0 AND g.user_id=:user_id', 'LEFT')
                ->where('f.user_id', $this->userInfo['id'])
                ->where("f.friend_id=:keyword OR f.remark LIKE :likeyword OR u.nickname LIKE :likeyword OR fu.nickname LIKE :likeyword OR a.nickname LIKE :likeyword")
                ->bind([
                    'keyword'   => $data['keyword'],
                    'likeyword' => '%' . $data['keyword'] . '%',
                    'user_id'   => $this->userInfo['id']
                ])
                ->order('f.createtime desc')
                ->select(false);
            $friends   = Db::query($friendSql);
            foreach ($friends as $key => $info) {
                $friends[$key]['id']              = $info['friend_id'];
                $friends[$key]['nickname_origin'] = Common::trueAttr(Common::nicknameSort([
                    $friends[$key]['nickname'],
                    $info['fu_nickname'],
                    $info['a_nickname']
                ], $friends[$key]['id']));

                $friends[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $info['remark'],
                    $friends[$key]['nickname_origin']
                ], $friends[$key]['id']));
                $friends[$key]['avatar']   = Common::avatarSrc([
                    $info['avatar'],
                    $info['fu_avatar'],
                    $info['a_avatar']
                ], $friends[$key]['nickname']);

                $friends[$key]['groupname'] = $friends[$key]['groupname'] ? $friends[$key]['groupname'] : '全部好友';

                unset($friends[$key]['fu_avatar'], $friends[$key]['a_avatar'], $friends[$key]['fu_nickname'], $friends[$key]['a_nickname']);
            }
        }

        // 从会话中搜索好友
        if (in_array('lately-session-user', $method)) {
            $session = $this->loadSessionList([
                'method'  => 'pickuser',
                'keyword' => $data['keyword']
            ]);

            $latelySessionUser = array_values($session);
        }

        // 搜索群聊
        if (in_array('group-chat', $method)) {
            $groupChat = Db::name('fastim_group_user')
                ->alias('gu')
                ->field('gu.group_id, gu.user_id, gu.user_group_id, gu.jointime, gc.id, gc.avatar, gc.nickname, g.name as groupname')
                ->join('fastim_group_chat gc', 'gu.group_id=gc.id')
                ->join('fastim_group g', 'gu.user_group_id=g.id AND g.type=1 AND g.user_id=:user_id', 'LEFT')
                ->where('gu.user_id', $this->userInfo['id'])
                ->where('gc.id=:keyword OR gc.nickname LIKE :likeyword')
                ->bind([
                    'user_id'   => $this->userInfo['id'],
                    'keyword'   => $data['keyword'],
                    'likeyword' => '%' . $data['keyword'] . '%'
                ])
                ->order('gu.jointime desc')
                ->select();
            foreach ($groupChat as $key => $value) {
                $groupChat[$key]['avatar']    = Common::avatarSrc([
                    $value['avatar']
                ], $groupChat[$key]['nickname']);
                $groupChat[$key]['groupname'] = $value['groupname'] ? $value['groupname'] : '全部群聊';
            }
        }

        // 搜索全部会话
        if (in_array('lately-session', $method)) {
            $session       = $this->loadSessionList([
                'keyword' => $data['keyword']
            ]);
            $latelySession = array_values($session);
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'user_search',
            'data'  => [
                'friends'             => $friends ?? [],
                'lately_session_user' => $latelySessionUser ?? [],
                'group_chat'          => $groupChat ?? [],
                'lately_session'      => $latelySession ?? [],
                'data'                => $data
            ]
        ]));
    }

    /**
     * uni-app端加载好友和群聊
     * @param  [type] $data [description]
     * @return [type]       [description]
     */
    public function loadContact($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['method'], $data)) {
            return;
        }

        if ($data['method'] == 'all-friend' || $data['method'] == 'top-friend') {
            $where['f.user_id'] = $this->userInfo['id'];
            if ($data['method'] == 'top-friend') {
                $where['f.top_contacts'] = 1;
            }

            $res = Db::name('fastim_friendship')
                ->alias('f')
                ->field('f.*,u.avatar,u.nickname,u.status,fu.avatar as fu_avatar,fu.nickname as fu_nickname,a.avatar as a_avatar,a.nickname as a_nickname')
                ->join('fastim_user u', 'f.friend_id=u.id')
                ->join('user fu', 'u.user_id=fu.id', 'LEFT')
                ->join('admin a', 'u.admin_id=a.id', 'LEFT')
                ->where($where)
                ->order('f.createtime asc')
                ->select();
            foreach ($res as $key => $info) {
                $res[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $info['remark'],
                    $res[$key]['nickname'],
                    $info['fu_nickname'],
                    $info['a_nickname']
                ], $info['friend_id']));

                $res[$key]['avatar'] = Common::avatarSrc([
                    $info['avatar'],
                    $info['fu_avatar'],
                    $info['a_avatar']
                ], $res[$key]['nickname']);

                unset($res[$key]['fu_avatar'], $res[$key]['a_avatar'], $res[$key]['fu_nickname'], $res[$key]['a_nickname']);
            }

            $initialPinyinArr = Common::initialPinyinArrSort($res, 'nickname');
        } elseif ($data['method'] == 'all-group-chat') {
            $res = Db::name('fastim_group_user')
                ->alias('gu')
                ->field('gc.*,gu.jointime')
                ->where('gu.user_id', $this->userInfo['id'])
                ->where('gc.deletetime', null)
                ->join('fastim_group_chat gc', 'gu.group_id=gc.id')
                ->order('gu.jointime asc')
                ->select();

            foreach ($res as $key => $value) {
                $res[$key]['avatar'] = Common::avatarSrc([
                    $value['avatar']
                ], $res[$key]['nickname']);
            }

            $initialPinyinArr = Common::initialPinyinArrSort($res, 'nickname');
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'load_contact',
            'data'  => [
                'res'  => $initialPinyinArr,
                'data' => $data
            ]
        ]));
    }

    /**
     * 加载分组内的好友或群聊
     */
    public function loadGroup($data)
    {
        if (!$this->swooleCommon->requiredParamCheck(['id', 'method'], $data, false, ['id' => '分组找不到啦~'])) {
            return;
        }

        $group = Common::getGroupInfo($data['id']);
        if (!$group) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '分组找不到啦~'
            ]));
            return;
        }

        if (!isset($data['page']) || $data['page'] == 1) {
            $min = 0;
        } else {
            $min = ($data['page'] - 1) * $this->pageCount;
        }

        if ($group['type'] == 0) {
            // 好友
            $where['f.user_id'] = $this->userInfo['id'];
            if ($data['id'] == 'common') {
                // 获取常用联系人
                $where['f.top_contacts'] = 1;
            } elseif ($data['id'] != 'all_friends') {
                $where['f.group'] = $data['id'];
            }

            $res = Db::name('fastim_friendship')
                ->alias('f')
                ->field('f.*,u.avatar,u.nickname,u.status,u.bio,u.gender,fu.avatar as fu_avatar,fu.nickname as fu_nickname,fu.bio as fu_bio,fu.gender as fu_gender,a.avatar as a_avatar,a.nickname as a_nickname')
                ->join('fastim_user u', 'f.friend_id=u.id')
                ->join('user fu', 'u.user_id=fu.id', 'LEFT')
                ->join('admin a', 'u.admin_id=a.id', 'LEFT')
                ->where($where);

            if ($data['method'] == 'pick-group-user') {
                $res = $res->order('f.createtime asc')->select();
            } else {
                $res = $res->order('f.createtime desc')->limit($min, $this->pageCount)->select();
            }

            foreach ($res as $key => $info) {
                $res[$key]['nickname_origin'] = Common::trueAttr(Common::nicknameSort([
                    $res[$key]['nickname'],
                    $info['fu_nickname'],
                    $info['a_nickname']
                ], $info['friend_id']));

                $res[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $info['remark'],
                    $res[$key]['nickname_origin']
                ], $info['friend_id']));
                $res[$key]['avatar']   = Common::avatarSrc([
                    $info['avatar'],
                    $info['fu_avatar'],
                    $info['a_avatar']
                ], $res[$key]['nickname']);
                $res[$key]['bio']      = Common::trueAttr([
                    $info['bio'],
                    $info['fu_bio'],
                    '这家伙很懒，什么也没写！'
                ]);
                $res[$key]['gender']   = Common::trueAttr([
                    $info['gender'],
                    $info['fu_gender'],
                    '0'
                ]);
                $res[$key]['gender']   = Common::imUserGender($info['gender']);
                $res[$key]['status']   = Common::imUserStatus($info['status']);
                unset($res[$key]['fu_avatar'], $res[$key]['a_avatar'], $res[$key]['fu_nickname'], $res[$key]['a_nickname'], $res[$key]['fu_bio'], $res[$key]['fu_gender']);
            }
            $data['type'] = 'user';
        } elseif ($group['type'] == 1) {
            // 群聊-取得分组中的群聊
            if ($data['id'] == 'all_group') {
                // 全部分组
                $join = [
                    ['fastim_group g', 'gu.user_group_id=g.id', 'LEFT']
                ];
            } else {
                $join = [
                    ['fastim_group g', 'gu.user_group_id=g.id AND g.id=' . (int)$data['id']]
                ];
            }

            $dbprefix = config('database.prefix');
            $res      = Db::name('fastim_group_user')
                ->alias('gu')
                ->field('gc.*, gu.user_group_id, gu.jointime, g.name as groupname,(SELECT count(user_id) FROM `' . $dbprefix . 'fastim_group_user` `guc` WHERE guc.group_id=gu.group_id) as user_count')
                ->join('fastim_group_chat gc', 'gu.group_id=gc.id')
                ->join($join)
                ->where('gu.user_id', $this->userInfo['id']);

            if ($data['method'] == 'pick-group-user') {
                $res = $res->order('gu.jointime asc')->select();
            } else {
                $res = $res->order('gu.jointime desc')->limit($min, $this->pageCount)->select();
            }

            foreach ($res as $key => $value) {
                $res[$key]['avatar'] = Common::avatarSrc([
                    $value['avatar']
                ], $res[$key]['nickname']);
                $res[$key]['bio']    = Common::trueAttr([
                    $value['bio'],
                    '群主很懒，什么也没写~'
                ]);
            }

            $data['type'] = 'group_chat';
        } elseif ($group['type'] == 2) {
            // 收藏
            $where['user_id'] = $this->userInfo['id'];

            $cType = CommonCode::nonPrivilegedMessage(false, ['other']);
            if (in_array($data['id'], $cType)) {
                $where['type'] = $data['id'];
            } elseif ($data['id'] == 'all_collection') {
                // 
            }

            if (isset($data['keywords']) && $data['keywords']) {
                $where['value'] = ['LIKE', '%' . $data['keywords'] . '%'];
            }

            $res = Db::name('fastim_user_collection')
                ->where($where)
                ->order('createtime desc')
                ->limit($min, $this->pageCount)
                ->select();

            foreach ($res as $key => $value) {
                if (in_array($value['type'], CommonCode::$messageJsonTypes)) {
                    $res[$key]['message'] = json_decode($value['value'], true);
                } else {
                    $res[$key]['message'] = htmlspecialchars_decode($value['value']);
                }
                $res[$key]['createtime'] = Common::formatTime($value['createtime']);
                unset($res[$key]['value']);
            }
        }

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'load_group',
            'data'  => [
                'res'      => $res,
                'data'     => $data,
                'group'    => $group,
                'nextpage' => (count($res) < $this->pageCount) ? false : true,
            ]
        ]));
    }

    /**
     * 搜索新联系人/群
     */
    public function searchNewContact($data)
    {
        if (!isset($data['keyword']) || !trim($data['keyword'])) {
            $this->server->push($this->frame->fd, json_encode([
                'event' => 'show_msg',
                'data'  => '请输入搜索关键词~'
            ]));
            return false;
        }

        if (!isset($data['page']) || $data['page'] == 1) {
            $min = 0;
        } else {
            $min = ($data['page'] - 1) * $this->pageCount;
        }

        if ($data['type'] == 'friends') {

            $searchSql = Db::name('fastim_user')
                ->alias('u')
                ->field('u.id,u.avatar,u.nickname,u.status,u.bio,u.gender,u.mobile,u.email,fu.avatar as fu_avatar,fu.nickname as fu_nickname,fu.bio as fu_bio,fu.gender as fu_gender,fu.mobile as fu_mobile,fu.email as fu_email,a.avatar as a_avatar,a.nickname as a_nickname,a.email as a_email,fr.friend_id as is_friend,fr.remark')
                ->join('user fu', 'u.user_id=fu.id', 'LEFT')
//                ->join('users fu', 'u.user_id=fu.id', 'LEFT')
                ->join('admin a', 'u.admin_id=a.id', 'LEFT')
                ->join('fastim_friendship fr', 'fr.user_id=:uid AND fr.friend_id=u.id', 'LEFT')
                ->where("u.id=:keyword OR u.mobile=:keyword OR u.email=:keyword OR fu.mobile=:keyword OR fu.email=:keyword OR a.email=:keyword OR fu.nickname LIKE :likeyword OR a.nickname LIKE :likeyword")
                ->where('u.id', '<>', $this->userInfo['id'])
                ->bind([
                    'keyword'   => $data['keyword'],
                    'likeyword' => '%' . $data['keyword'] . '%',
                    'uid'       => $this->userInfo['id']
                ])
                ->limit($min, $this->pageCount)
                ->select(false);

            $res = Db::query($searchSql);

            $addMyWayField = [
                0 => ['eq', ['id']],
                1 => ['like', ['nickname', 'fu_nickname', 'a_nickname']],
                2 => ['eq', ['mobile', 'fu_mobile']],
                3 => ['eq', ['email', 'fu_email', 'a_email']],
            ];
            foreach ($res as $key => $value) {
                // 检查添加方式
                $retain   = false;
                $addMyWay = Common::imUserConfig($value['id'], 'add_my_way');
                if ($addMyWay !== '') {
                    $addMyWay = explode(',', $addMyWay);
                    foreach ($addMyWay as $item) {
                        foreach ($addMyWayField[$item][1] as $itemField) {
                            if ($value[$itemField]) {
                                if ($addMyWayField[$item][0] == 'eq') {
                                    if ($data['keyword'] == $value[$itemField]) {
                                        $retain = true;
                                    }
                                } else {
                                    if (mb_stristr($value[$itemField], $data['keyword']) !== false) {
                                        $retain = true;
                                    }
                                }
                            }
                        }
                    }
                }
                if (!$retain) {
                    unset($res[$key]);
                    continue;
                }

                $res[$key]['nickname'] = Common::trueAttr(Common::nicknameSort([
                    $value['remark'],
                    $value['nickname'],
                    $value['fu_nickname'],
                    $value['a_nickname']
                ], $value['id']));

                $res[$key]['avatar'] = Common::avatarSrc([
                    $value['avatar'],
                    $value['fu_avatar'],
                    $value['a_avatar']
                ], $res[$key]['nickname']);

                $res[$key]['bio'] = Common::trueAttr([
                    $value['bio'],
                    $value['fu_bio'],
                    '这家伙很懒，什么也没写！'
                ]);

                $res[$key]['gender'] = Common::trueAttr([
                    $value['gender'],
                    $value['fu_gender'],
                    '0'
                ]);
                $res[$key]['gender'] = Common::imUserGender($res[$key]['gender']);
                $res[$key]['status'] = Common::imUserStatus($value['status']);

                unset($res[$key]['fu_avatar'], $res[$key]['a_avatar'], $res[$key]['fu_nickname'], $res[$key]['a_nickname'], $res[$key]['fu_bio'], $res[$key]['fu_gender'], $res[$key]['mobile'], $res[$key]['fu_mobile'], $res[$key]['email'], $res[$key]['fu_email'], $res[$key]['a_email']);
            }
        } elseif ($data['type'] == 'group') {
            $dbprefix = config('database.prefix');
            $res      = Db::name('fastim_group_chat')
                ->alias('g')
                ->field('g.*, (SELECT count(user_id) FROM `' . $dbprefix . 'fastim_group_user` `gu` WHERE gu.group_id=g.id) as user_count, gru.user_id as is_group_user')
                ->join('fastim_group_user gru', 'gru.group_id=g.id AND gru.user_id=:uid', 'LEFT')
                ->where(function ($query) use ($data) {
                    $query->where('g.id', $data['keyword']);
                    $query->whereOr('g.nickname', 'like', '%' . $data['keyword'] . '%');
                })
                ->where('g.deletetime', null)
                ->bind([
                    'uid' => $this->userInfo['id']
                ])
                ->order('g.createtime desc')
                ->limit($min, $this->pageCount)
                ->select();
            foreach ($res as $key => $value) {

                if ($value['retrieval_settings'] == 0) {
                    unset($res[$key]);
                    continue;
                }

                $res[$key]['avatar'] = Common::avatarSrc([
                    $value['avatar'],
                ], $value['nickname']);

                $res[$key]['bio'] = Common::trueAttr([
                    $value['bio'],
                    '群主很懒，什么也没写~'
                ]);
            }
        }

        $res = array_values($res);
        $this->server->push($this->frame->fd, json_encode([
            'event' => 'search_new_contact',
            'data'  => [
                'res'      => $res,
                'data'     => $data,
                'nextpage' => (count($res) < $this->pageCount) ? false : true,
            ]
        ]));
    }

    /**
     * uni-app用户中心-待办和收藏数量
     */
    public function center($data)
    {
        $info            = Common::getImUserInfo($this->userInfo['id'], true, $this->userInfo['id']);
        $collectionCount = Db::name('fastim_user_collection')->where('user_id', $this->userInfo['id'])->count();

        $TODOCount = Db::name('fastim_todo')
            ->where('user_id', $this->userInfo['id'])
            ->where('status', '0')
            ->where('deletetime', null)
            ->count();

        $this->server->push($this->frame->fd, json_encode([
            'event' => 'center',
            'data'  => [
                'info'            => $info,
                'data'            => $data,
                'collectionCount' => $collectionCount,
                'TODOCount'       => $TODOCount
            ]
        ]));
    }
}