package com.yonge.cooleshow.auth.service.impl;

import com.alibaba.fastjson.JSON;
import com.yonge.cooleshow.api.feign.AdminFeignService;
import com.yonge.cooleshow.api.feign.dto.ApiWrapper;
import com.yonge.cooleshow.auth.api.dto.QRLoginDto;
import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
import com.yonge.cooleshow.auth.api.dto.SysUserInfo;
import com.yonge.cooleshow.auth.api.dto.SysUserQueryInfo;
import com.yonge.cooleshow.auth.api.dto.UserSetReq;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.auth.api.vo.UserSetVo;
import com.yonge.cooleshow.auth.config.RongCloudConfig;
import com.yonge.cooleshow.auth.core.service.CustomTokenServices;
import com.yonge.cooleshow.auth.dal.dao.SysUserDao;
import com.yonge.cooleshow.auth.dal.wrapper.LogOffWrapper;
import com.yonge.cooleshow.auth.enums.EClientType;
import com.yonge.cooleshow.auth.service.SysConfigService;
import com.yonge.cooleshow.auth.service.SysRoleMenuService;
import com.yonge.cooleshow.auth.service.SysUserRoleService;
import com.yonge.cooleshow.auth.service.SysUserService;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.entity.ImUserModel;
import com.yonge.cooleshow.common.enums.CacheNameEnum;
import com.yonge.cooleshow.common.enums.SysUserType;
import com.yonge.cooleshow.common.enums.UserFirstTimeTypeEnum;
import com.yonge.cooleshow.common.enums.YesOrNoEnum;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.mybatis.dal.BaseDAO;
import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
import io.rong.models.response.TokenResult;
import io.rong.models.user.UserModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@Service
@RefreshScope
public class SysUserServiceImpl extends BaseServiceImpl<Long, SysUser> implements SysUserService {

    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserRoleService sysUserRoleService;
    @Autowired
    private SysRoleMenuService sysRoleMenuService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private RedissonClient redissonClient;
    @Resource
    private AdminFeignService adminFeignService;

    @Resource
    private CustomTokenServices tokenService;

    @Override
    public BaseDAO<Long, SysUser> getDAO() {
        return sysUserDao;
    }

    @Override
    public SysUser queryByUsername(String username) {
        return sysUserDao.queryByUsername(username);
    }

    @Override
    public SysUser queryByPhone(String phone) {
        return sysUserDao.queryByPhone(phone);
    }

    @Override
    public SysUser queryLockByPhone(String phone) {
        return sysUserDao.queryLockByPhone(phone);
    }

    @Override
    public SysUser queryByPhoneAndClient(String phone, String client) {
        return sysUserDao.queryByPhoneAndClient(phone, client);
    }

    @Override
    public SysUserInfo queryUserInfoByUsername(String username) {
        return getSysUserInfo(queryByUsername(username));
    }

    @Override
    public SysUserInfo queryUserInfoByPhone(String phone) {
        return getSysUserInfo(queryLockByPhone(phone));
    }

    @Override
    public SysUserInfo queryUserInfoByPhoneAndClient(String phone, String client) {
        return getSysUserInfo(queryByPhoneAndClient(phone, client));
    }

    private SysUserInfo getSysUserInfo(SysUser sysUser) {
        if (sysUser == null) {
            return null;
        }
        SysUserInfo userInfo = new SysUserInfo();
        userInfo.setSysUser(sysUser);

        List<String> roleCodeList = sysUserRoleService.queryRoleCodeListByUserId(sysUser.getId());
        userInfo.setRoles(roleCodeList.toArray(new String[0]));

        List<Long> roleIdList = sysUserRoleService.queryRoleIdListByUserId(sysUser.getId());
        List<String> permissionList = sysRoleMenuService.queryPermissionsByRoleIdList(roleIdList);

        userInfo.setPermissions(permissionList.toArray(new String[0]));

        return userInfo;
    }

    @Override
    public void updatePassword(String mobile, String password) {
        sysUserDao.updatePassword(mobile, password);
    }

    @Override
    public Long add(SysUser sysUser) {
        sysUserDao.insert(sysUser);
        return sysUser.getId();
    }

    @Override
    public ImUserModel getBasic(Long userId) {
        return sysUserDao.getBasic(userId);
    }

    @Override
    public void updateBaseInfo(SysUser sysUser) {
        sysUserDao.update(sysUser);
    }

    @Override
    public SysUser queryUserInfo(Long userId) {
        return sysUserDao.get(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SysUserInfo registerUser(String phone, String clientId, String loginUserType) {

        SysUserInfo userInfo = null;
        if (StringUtils.equalsIgnoreCase(loginUserType, "TEACHER")) {
            userInfo = registerTeacher(phone);
        } else if (StringUtils.equalsIgnoreCase(loginUserType, "STUDENT")) {
            userInfo = registerStudent(phone);
        } else if (StringUtils.equalsIgnoreCase(clientId, "TEACHER")) {
            userInfo = registerTeacher(phone);
        } else if (StringUtils.equalsIgnoreCase(clientId, "STUDENT")) {
            userInfo = registerStudent(phone);
        }

        return userInfo;
    }

    private SysUserInfo registerTeacher(String phone) {
        SysUser sysUser = new SysUser();
        sysUser.setPhone(phone);
        String defaultHeard = sysConfigService.findConfigValue(SysConfigConstant.DEFAULT_HEARD);
        sysUser.setAvatar(defaultHeard);
        sysUser.setGender(1);
        sysUser.setUserType("TEACHER");
        sysUserDao.insert(sysUser);
        //创建teacher表
        saveTeacher(sysUser);
        //用户默认昵称
        sysUser.setUsername("游客" + sysUser.getId());
        sysUserDao.update(sysUser);

        return queryUserInfoByPhone(phone);
    }

    private SysUserInfo registerStudent(String phone) {
        SysUser sysUser = new SysUser();
        sysUser.setPhone(phone);
        String defaultHeard = sysConfigService.findConfigValue(SysConfigConstant.DEFAULT_HEARD);
        sysUser.setAvatar(defaultHeard);
        sysUser.setGender(1);
        sysUser.setUserType("STUDENT");
        sysUserDao.insert(sysUser);
        saveStudent(sysUser);

        //用户默认昵称
        sysUser.setUsername("游客" + sysUser.getId());
        sysUserDao.update(sysUser);

        return queryUserInfoByPhone(phone);
    }

    /**
     * 添加系统客服好友消息
     * @param sysUser SysUser
     */
    public void sendSysCustomerServiceFriendMessage(SysUser sysUser, String clientType) {

        /*try {

            ThreadPool.getExecutor().submit(() -> {

                SysUser customerService = sysUserDao.getCustomerServiceByFriendLeast();
                if (customerService != null) {
                    // 发送添加系统客服好友消息
                    HttpResponseResult<Boolean> result = adminFeignService.customerService(UserFriendInfoVO.builder()
                            .userId(sysUser.getId())
                            .clientType(clientType)
                            .friendIds(Lists.newArrayList(customerService.getId()))
                            .build());
                    log.info("sendSysCustomerServiceFriendMessage mobile={}, ret={}", customerService.getPhone(), JSON.toJSONString(result));
                }

            });

        } catch (Exception e) {
            log.error("sendSysCustomerServiceFriendMessage userId={}", sysUser.getId(), e);
        }*/

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refreshImToken(SysUser sysUser) {
        sysUserDao.refreshImToken(sysUser.getId(), sysUser.getImToken());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveStudent(SysUser sysUser) {
        sysUserDao.saveStudent(sysUser.getId());
        sysUserDao.createUserAccount(sysUser.getId());

        //记录注册时间
        adminFeignService.recordTime(sysUser.getId(), SysUserType.STUDENT.getCode(), UserFirstTimeTypeEnum.REGISTER_STUDENT);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveTeacher(SysUser sysUser) {
        sysUserDao.saveTeacher(sysUser.getId());
        sysUserDao.createUserAccount(sysUser.getId());

        //记录注册时间
        adminFeignService.recordTime(sysUser.getId(), SysUserType.TEACHER.getCode(), UserFirstTimeTypeEnum.REGISTER_TEACHER);
    }

    @Override
    public void updateUserCard(RealnameAuthReq realNameAuthDto) {
        sysUserDao.updateUserCard(realNameAuthDto);
    }

    @Override
    public UserSetVo getSetDetail(Long id) {
        return sysUserDao.getSetDetail(id);
    }

    @Override
    public void submitSetDetail(UserSetReq setReq, Long id) {
        sysUserDao.updatetSetDetail(setReq, id);

        if (StringUtils.isEmpty(setReq.getClientType())) {
            setReq.setClientType(EClientType.TEACHER.name());
        }
        //更新融云用户基本信息
        this.updateRongCloudUserInfo(id, setReq.getClientType());

        // 更新老师、学生头像
        String clientId = setReq.getClientId();
        if(StringUtils.isEmpty(clientId)) {
            clientId =setReq.getClientType();
        }
        if (StringUtils.isNotEmpty(setReq.getAvatar()) && StringUtils.isNotEmpty(clientId)) {
            if (EClientType.STUDENT.getCode().equals(setReq.getClientType()) ||
                    EClientType.TEACHER.getCode().equals(setReq.getClientType()) ||
                    EClientType.SYSTEM.getCode().equals(setReq.getClientType())) {
                sysUserDao.updateAvatar(clientId, setReq.getAvatar(), id);
            }
        }
    }

    @Override
    public void updateRongCloudUserInfo(Long userId, String clientType) {
        UserSetVo setDetail = this.getSetDetail(userId);
        //更新imGroupMember表用户头像
        sysUserDao.updateImGroupMember(userId, setDetail.getUsername(), setDetail.getAvatar());
        //更新imUserFriend表用户头像
        sysUserDao.updateImUserFriend(userId, setDetail.getUsername(), setDetail.getAvatar());
        try {
            adminFeignService.register(userId.toString(),clientType, setDetail.getUsername(), setDetail.getAvatar());
        } catch (Exception e) {
            throw new BizException("更新用户信息失败");
        }
    }

    @Override
    public List<SysUser> queryEmployeeList(SysUserQueryInfo queryInfo) {
        return sysUserDao.queryEmployeeList(queryInfo);
    }

    @Override
    public boolean verifyQrCode(String phone, String qrCode) {
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(qrCode)) {
            return false;
        }
        Object data = redissonClient.getBucket(CacheNameEnum.QR_LOGIN_CODE.getRedisKey(qrCode))
                .get();
        if (null == data) {
            return false;
        }
        QRLoginDto dto = (QRLoginDto) data;
        if (phone.equals(dto.getPhone()) && qrCode.equals(dto.getCode())) {
            return true;
        }
        return false;
    }

    @Override
    public void logoffById(Long id) {
        //判断用户是否有未结束的课程
        Integer num = sysUserDao.getUnCompCourseNum(id);
        if (num > 0) {
            throw new BizException("用户有未完成的课程");
        }

        List<SysUser> sysUsers = sysUserDao.queryHistoryUserById(id);
        Integer maxVersion = 0;
        if (!CollectionUtils.isEmpty(sysUsers)) {
            for (SysUser sysUser : sysUsers) {
                String[] split = sysUser.getPhone().split("\\+");
                if (split.length == 2) {
                    String version = split[0].substring(1);
                    if (maxVersion < Integer.parseInt(version)) {
                        maxVersion = Integer.parseInt(version);
                    }
                }
            }
        }
        maxVersion += 1;
        sysUserDao.logoffById(id, maxVersion);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateLockStatus(Long userId, Integer lockFlag, String sysUserType) {
        sysUserDao.updateLockStatus(userId, lockFlag, sysUserType);

        // 系统员工锁定，清除客服绑定关系
        if (lockFlag == YesOrNoEnum.YES.getCode().intValue() && SysUserType.SYSTEM.getCode().equals(sysUserType)) {
            // 清除客服绑定关系
            adminFeignService.clearCustomerService(userId, sysUserType);
        }
    }

    /**
     * 用户信息
     *
     * @param userId     用户ID
     * @param clientType 客户端类型
     * @return SysUser
     */
    @Override
    public SysUser queryUserInfoWithIMToken(Long userId, EClientType clientType) {

        // 查询用户基本信息
        SysUser sysUser = sysUserDao.get(userId);

        if (EClientType.STUDENT == clientType && Objects.nonNull(sysUser)) {
            // 重新请求生成IM会话TOKEN
            try {
                String name = sysUser.getUsername();
                if(StringUtils.isEmpty(name)){
                    name = sysUser.getRealName();
                }

                // IM用户ID
                String imIdentity = MessageFormat.format("{0}:{1}", String.valueOf(sysUser.getId()), clientType.name());

                TokenResult result = RongCloudConfig.rongCloud.user.register(new UserModel(imIdentity, name, sysUser.getAvatar()));
                if(result.code.equals(200)){

                    sysUser.setImToken(result.getToken());
                } else {
                    log.warn("queryUserInfoWithIMToken 获取用户token失败:{}", result.errorMessage);
                }

            } catch (Exception e) {
                log.error("queryUserInfoWithIMToken 获取用户token失败, userId={}", userId, e);
            }
        }

        return sysUser;
    }

    @Override
    public Long getTenantByClient(Long userId, String clientId) {
        // 查询用户机构信息，若没有则返回-1
        return Optional.ofNullable(sysUserDao.getTenantByClient(userId, clientId.toUpperCase())).orElse(-1L);
    }

    /**
     * 根据openId获取用户信息
     *
     * @param openId 用户openId
     * @param clientId 客户端ID
     * @return SysUser
     */
    @Override
    public SysUser getSysUserByOpenId(String openId, String clientId) {
        return sysUserDao.getSysUserByOpenId(openId, clientId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResponseResult<Void> logoffByPhone(String phone) {
        // todo: 暂时不上
        try {
            HttpResponseResult<List<ApiWrapper.LogOff>> check = adminFeignService.accountLogoffCheck(phone);
            if (!check.getStatus()) {
                log.error("logoffByPhone check error", check.getMsg());
                throw new BizException("数据检查失败");
            }
            List<ApiWrapper.LogOff> errMsg = check.getData();
            if (!CollectionUtils.isEmpty(errMsg)) {
                return HttpResponseResult.failed(5201, null, JSON.toJSONString(errMsg));
            }
        } catch (Exception e) {
            log.error("logoffByPhone check error", e);
            throw new BizException("数据检查失败");
        }
        SysUser sysUser = sysUserDao.queryByPhone(phone);
        int num = sysUserDao.countByPhone(phone);
        //冻结相关所有客户端账号
        sysUserDao.updateLockStatusByPhone(phone);
        //注销用户
        int i = sysUserDao.logoffByPhone(num,phone);
        if(i < 1){
            throw new BizException("用户不存在或已注销");
        }

        // 修改名称 和头像
        sysUserDao.updateNameAndImg(sysUser.getId());
        // 解散群、退群、删除好友关系
        adminFeignService.logoffQuitImGroup(phone);

        //退出登录
        tokenService.revokeTokenByPhone(phone);
        return HttpResponseResult.succeed();
    }

    @Override
    public HttpResponseResult<List<String>> logoffCheckByPhone(String phone) {
//        HttpResponseResult<List<ApiWrapper.LogOff>> check = adminFeignService.accountLogoffCheck(phone);
//        if (check == null) {
//            throw new BizException("数据检查失败");
//        }
//        List<ApiWrapper.LogOff> errMsg = check.getData();
//        if (!CollectionUtils.isEmpty(errMsg)) {
//            return HttpResponseResult.failed(500, errMsg, "存在未处理事项");
//        }
        return HttpResponseResult.succeed();
    }

    @Override
    public void updateStudentHideFlag(Long userId, int hideFlag) {
        sysUserDao.updateStudentHideFlag(userId, hideFlag);
    }
}
