package com.yonge.cooleshow.biz.dal.service.impl;

import com.dayaedu.cbs.common.enums.EAppKey;
import com.dayaedu.cbs.common.enums.EClientType;
import com.dayaedu.cbs.openfeign.client.MessageFeignClientService;
import com.dayaedu.cbs.openfeign.wrapper.message.CbsMessageWrapper;
import com.google.common.collect.Lists;
import com.microsvc.toolkit.common.response.template.R;
import com.yonge.cooleshow.api.feign.MallPortalFeignService;
import com.yonge.cooleshow.api.feign.dto.ApiWrapper;
import com.yonge.cooleshow.api.feign.enums.CheckStatus;
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
import com.yonge.cooleshow.auth.api.dto.RealnameAuthReq;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.biz.dal.dao.MusicSheetAuthRecordDao;
import com.yonge.cooleshow.biz.dal.dao.MusicSheetDao;
import com.yonge.cooleshow.biz.dal.entity.CourseGroup;
import com.yonge.cooleshow.biz.dal.entity.ImGroup;
import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
import com.yonge.cooleshow.biz.dal.entity.ImUserFriend;
import com.yonge.cooleshow.biz.dal.entity.Student;
import com.yonge.cooleshow.biz.dal.entity.Teacher;
import com.yonge.cooleshow.biz.dal.entity.UserOrder;
import com.yonge.cooleshow.biz.dal.entity.UserOrderRefund;
import com.yonge.cooleshow.biz.dal.entity.VideoLessonGroup;
import com.yonge.cooleshow.biz.dal.enums.*;
import com.yonge.cooleshow.biz.dal.enums.im.EImGroupMemberRoleType;
import com.yonge.cooleshow.biz.dal.mapper.SysUserMapper;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.service.im.ImGroupCoreService;
import com.yonge.cooleshow.biz.dal.vo.UserAccountVo;
import com.yonge.cooleshow.biz.dal.wrapper.UserInfoWrapper;
import com.yonge.cooleshow.common.entity.HttpResponseResult;
import com.yonge.cooleshow.common.enums.ContractTemplateTypeEnum;
import com.yonge.cooleshow.common.enums.SysUserType;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import com.yonge.toolset.thirdparty.user.realname.RealnameAuthenticationPlugin;
import com.yonge.toolset.utils.idcard.IdcardInfoExtractor;
import com.yonge.toolset.utils.idcard.IdcardValidator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SysUserServiceImpl implements SysUserService {

    @Resource
    private SysUserFeignService sysUserFeignService;
    @Resource
    private RealnameAuthenticationPlugin realnameAuthenticationPlugin;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private SysUserContractRecordService sysUserContractRecordService;
    @Resource
    private StudentService studentService;
    @Resource
    private TeacherService teacherService;
    @Resource
    private MessageSenderPluginContext messageSenderPluginContext;

    @Autowired
    private UserOrderService userOrderService;

    @Autowired
    private UserOrderRefundService userOrderRefundService;

    @Autowired
    private ImGroupMemberService imGroupMemberService;

    @Autowired
    private ImGroupService imGroupService;

    @Autowired
    private ImGroupCoreService imGroupCoreService;

    @Autowired
    private CourseGroupService courseGroupService;

    @Autowired
    private VideoLessonGroupService videoLessonGroupService;

    @Autowired
    private UserAccountService userAccountService;

    @Autowired
    private MallPortalFeignService mallPortalFeignService;

    @Autowired
    private ImUserFriendService imUserFriendService;

    @Autowired
    private MusicSheetDao musicSheetDao;

    @Autowired
    private MusicSheetAuthRecordDao musicSheetAuthRecordDao;

    @Resource
    private MessageFeignClientService messageFeignClientService;
    @Override
    public SysUserMapper getDao() {
        return sysUserMapper;
    }

    @Override
    public Long getUserId() {
        return Optional.ofNullable(sysUserFeignService.queryUserInfo()).
                map(SysUser::getId).
                orElseThrow(()-> new BizException("请登录"));
    }

    @Override
    public SysUser getUser() {
        Optional<SysUser> optional = Optional.ofNullable(sysUserFeignService.queryUserInfo());
        optional.map(SysUser::getId).
                orElseThrow(()-> new BizException("请登录"));
        return optional.get();
    }

    @Override
    public SysUser findUserById(Long userId) {
        Optional<SysUser> optional = Optional.ofNullable(sysUserFeignService.queryUserById(userId));
        optional.map(SysUser::getId).
                orElseThrow(()-> new BizException("用户信息不存在"));
        return optional.get();
    }

    @Override
    public Long getTenantByClient(Long userId, String clientId) {
        return sysUserFeignService.getTenantByClient(userId,clientId).getData();
    }

    @Override
    public IdcardInfoExtractor updateUserCard(RealnameAuthReq realNameAuthDto, SysUser sysUser,ClientEnum client) {
        IdcardValidator idcardValidator = new IdcardValidator();
        //验证身份证号合法性
        boolean validatedAllIdcard = idcardValidator.isValidatedAllIdcard(realNameAuthDto.getIdCardNo());
        if (!validatedAllIdcard) {
            throw new BizException("身份证号不合法");
        }
        //通过身份证号获取身份信息
        IdcardInfoExtractor idcardInfoExtractor = new IdcardInfoExtractor(realNameAuthDto.getIdCardNo(), validatedAllIdcard);
        //todo 通过环境，不做实名判断
        try {
            boolean verify = realnameAuthenticationPlugin.verify(realNameAuthDto.getRealName(), realNameAuthDto.getIdCardNo());
            if (!verify) {
                throw new BizException("未通过实名认证");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BizException("未通过实名认证");
        }

        if (realNameAuthDto.getSave()) {
            realNameAuthDto.setUserId(sysUser.getId());
            realNameAuthDto.setGender(idcardInfoExtractor.getGender());
            realNameAuthDto.setBirthday(idcardInfoExtractor.getBirthday());
            //实名认证通过后立刻保存
            sysUserMapper.updateUserCard(realNameAuthDto);
        }
        // 签订用户注册协议

        // 判断是否已经签署
        Boolean contractSign = sysUserContractRecordService.checkContractSign(sysUser.getId(),
                                                                              SysUserType.valueOf(client.getCode()),
                                                                              ContractTemplateTypeEnum.REGISTER);
        if (!contractSign && realNameAuthDto.getContract()) {
            sysUser.setRealName(realNameAuthDto.getRealName());
            sysUser.setIdCardNo(realNameAuthDto.getIdCardNo());
            sysUser.setGender(realNameAuthDto.getGender());
            sysUser.setBirthdate(realNameAuthDto.getBirthday());
            HttpResponseResult<Boolean> sign = sysUserContractRecordService.sign(ContractTemplateTypeEnum.REGISTER,
                                                                                 SysUserType.valueOf(client.getCode()),sysUser);
            if (!sign.getStatus() || !sign.getData()) {
                throw new BizException(sign.getMsg());
            }
        }
        return idcardInfoExtractor;
    }

    @Override
    public Map<Long, com.yonge.cooleshow.biz.dal.entity.SysUser> getMapByIds(List<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return new HashMap<>();
        }
        List<com.yonge.cooleshow.biz.dal.entity.SysUser> sysUsers = sysUserMapper.selectBatchIds(userIds);
        if (CollectionUtils.isEmpty(sysUsers)) {
            return new HashMap<>();
        }
        return sysUsers.stream().collect(HashMap::new, (m, v) -> m.put(v.getId(), v), HashMap::putAll);
    }

    @Override
    public SysUser findUserByPhone(String phone) {

        return sysUserMapper.findUserByPhone(phone);
    }

    @Override
    public SysUser getByUserId(Long userId) {
        return sysUserMapper.getByUserId(userId);
    }


    @Override
    public void imDeviceId(UserInfoWrapper.UpdateUser info) {
        CbsMessageWrapper.UpdateDevice updateDevice = new CbsMessageWrapper.UpdateDevice();
        updateDevice.setUserId(info.getUserId().longValue());
        updateDevice.setDeviceIds(Lists.newArrayList(info.getImDeviceId()));
        updateDevice.setClientType(getClientType(info.getClient().getCode()));
        updateDevice.setAppKey(EAppKey.KLX);
        R<Boolean> booleanR = messageFeignClientService.updateDevice(updateDevice);
        if (booleanR != null && booleanR.feignData()) {
            switch (info.getClient()) {
                case STUDENT:
                case TENANT_STUDENT:
                    Student student = new Student();
                    student.setUserId(info.getUserId().longValue());
                    student.setImDeviceId(info.getImDeviceId());
                    studentService.updateById(student);

                    break;
                case TEACHER:
                    Teacher teacher = new Teacher();
                    teacher.setUserId(info.getUserId().longValue());
                    teacher.setImDeviceId(info.getImDeviceId());
                    teacherService.updateById(teacher);
                    break;
                default:
                    break;
            }
        }
    }

    @Override
    public List<ApiWrapper.LogOff> accountLogoffCheck(String phone) {
        SysUser sysUser = this.getDao().findUserByPhone(phone);
        if (sysUser == null || Boolean.TRUE.equals(sysUser.getDelFlag())) {
            throw new BizException("账号不存在");
        }
        Long userId = sysUser.getId();
        Map<String, List<String>> result = new HashMap<>();

        // 存在待支付、未确认收货、售后处理的订单
        Map<String, String> map = hasUnfinishedOrder(userId);
        if(map != null && map.size()>0){
            map.forEach((k,v)-> result.put(k, Lists.newArrayList("账号存在"+v+"的订单")));
        }

        Teacher teacher = teacherService.getById(userId);

        if (teacher != null) {
            List<String> errMsg = new ArrayList<>();
            // 存在群主身份
            List<ImGroupMember> groupMembers = imGroupMemberService.lambdaQuery()
                .eq(ImGroupMember::getUserId, userId)
                .eq(ImGroupMember::getGroupRoleType, EImGroupMemberRoleType.Owner)
                .list();
            List<String> groupIdList = groupMembers.stream().map(ImGroupMember::getGroupId).collect(Collectors.toList());
            if (!groupIdList.isEmpty()) {
                Collection<ImGroup> imGroups = imGroupService.listByIds(groupIdList);
                long orgGroups = imGroups.stream().filter(next -> ImGroupType.ORG.equals(next.getType())).count();
                if (orgGroups > 0) {
                    errMsg.add("账号为机构群群主，需要转移群主或解散群聊");
                }
            }

            // 存在进行中的课程
            // 趣纠课
            List<CourseGroup> list = courseGroupService.lambdaQuery()
                .eq(CourseGroup::getTeacherId, userId)
                .in(CourseGroup::getType, Arrays.asList("PRACTICE", "LIVE", "PIANO_ROOM_CLASS"))
                .in(CourseGroup::getStatus, Arrays.asList("ING", "APPLY", "NOT_SALE"))
                .list();
            String courseMsg ="";
            if (!CollectionUtils.isEmpty(list)) {
                List<String> courseTypes = list.stream().map(o -> o.getType()).distinct().collect(Collectors.toList());
                if (courseTypes.contains(CourseScheduleEnum.LIVE.name())) {
                    courseMsg += "直播课";
                }
                if (courseTypes.contains(CourseScheduleEnum.PRACTICE.name())){
                    if (courseMsg.length() > 0) {
                        courseMsg+="/";
                    }
                    courseMsg += "趣纠课";
                }
                if (courseTypes.contains(CourseScheduleEnum.PIANO_ROOM_CLASS.name())){
                    if (courseMsg.length() > 0) {
                        courseMsg+="/";
                    }
                    courseMsg += "琴房课";
                }
                if (courseMsg.length() > 0) {
                    courseMsg="账号存在未开始/进行中的" + courseMsg;
                }
            }
            // 视频课
            Integer videoCourse = videoLessonGroupService.lambdaQuery()
                .eq(VideoLessonGroup::getTeacherId, userId)
                .eq(VideoLessonGroup::getShelvesFlag, 1)
                .count();

            if (videoCourse > 0) {
                if (courseMsg.length() > 0) {
                    courseMsg+="和未下架的视频课";
                } else {
                    courseMsg="账号存在未下架的视频课";
                }
            } else {
                // 判断审核中的视频课

                videoCourse = videoLessonGroupService.lambdaQuery()
                    .eq(VideoLessonGroup::getTeacherId, userId)
                    .eq(VideoLessonGroup::getAuditStatus, AuthStatusEnum.DOING)
                    .count();
                if (videoCourse > 0) {
                    if (courseMsg.length() > 0) {
                        courseMsg+="和未下架的视频课";
                    } else {
                        courseMsg="账号存在未下架的视频课";
                    }
                }

            }
            if (courseMsg.length() > 0) {
                errMsg.add(courseMsg);
            }

            // 存在未提现的金额
            UserAccountVo detail = userAccountService.detail(userId);
            if (detail != null && (detail.getAmountTotal().compareTo(BigDecimal.ZERO) > 0
                || detail.getAmountUsable().compareTo(BigDecimal.ZERO) > 0
                || detail.getAmountFrozen().compareTo(BigDecimal.ZERO) > 0)
                || detail.getAmountUnrecorded().compareTo(BigDecimal.ZERO) > 0) {
                errMsg.add("收入未结算/推广计划未入账");
            }

            // 查询来源是老师的，用户未下架的曲目
            int i = musicSheetDao.countTeacherEnable(userId);
            if (i > 0) {
                errMsg.add("账号存在未下架曲目");
            } else {
                // 检查审核中的曲目
                int j = musicSheetAuthRecordDao.countTeacherAudit(userId);
                if (j > 0) {
                    errMsg.add("账号存在未下架曲目");
                }
            }
            List<String> strings = result.get(ClientEnum.TEACHER.name());
            if (strings == null) {
                strings = new ArrayList<>();
            }
            strings.addAll(errMsg);
            result.put(ClientEnum.TEACHER.name(), strings);

        }

        List<ApiWrapper.LogOff> logOffs = new ArrayList<>();
        result.forEach((k,v)->{
            if (CollectionUtils.isEmpty(v)) {
                return;
            }
            ApiWrapper.LogOff logOff = new ApiWrapper.LogOff();
            logOff.setClient(k);
            logOff.setErrList(v);
            logOffs.add(logOff);
        });


        return logOffs;
    }

    private Map<String, String> hasUnfinishedOrder(Long userId) {
        // 商城订单 0->待付款；1->待发货；2->已发货
        HttpResponseResult<Map<String, Set<CheckStatus>>> httpResponseResult = mallPortalFeignService.checkOrderStatus(userId);
        if (httpResponseResult == null) {
            throw new BizException("检查订单信息失败");
        }
        Map<String, Set<CheckStatus>> data = httpResponseResult.getData();
        if (data == null) {
            data = new HashMap<>();
        }

        // 酷乐秀订单
        List<UserOrder> list = userOrderService.lambdaQuery()
            .eq(UserOrder::getUserId, userId)
            .in(UserOrder::getStatus, Arrays.asList(OrderStatusEnum.WAIT_PAY, OrderStatusEnum.PAYING))
            .list();
        if (!CollectionUtils.isEmpty(list)) {
            for (UserOrder userOrder : list) {
                Set<CheckStatus> checkStatuses = data.get(userOrder.getOrderClient().name());
                if (checkStatuses == null) {
                    checkStatuses = new HashSet<>();
                }
                checkStatuses.add(CheckStatus.WAIT_PAY);
                data.put(userOrder.getOrderClient().name(), checkStatuses);
            }

        }

        // 退款订单
        List<UserOrderRefund> list1 = userOrderRefundService.lambdaQuery()
            .eq(UserOrderRefund::getUserId, userId)
            .eq(UserOrderRefund::getStatus, AuthStatusEnum.DOING)
            .list();
        if (!CollectionUtils.isEmpty(list1)) {
            // 订单id 集合
            Set<Long> orderIds = list1.stream().map(UserOrderRefund::getOrderId).collect(Collectors.toSet());
            List<UserOrder> userOrders = userOrderService.lambdaQuery()
                .in(UserOrder::getId, orderIds)
                .list();
            for (UserOrder userOrder : userOrders) {
                Set<CheckStatus> checkStatuses = data.get(userOrder.getOrderClient().name());
                if (checkStatuses == null) {
                    checkStatuses = new HashSet<>();
                }
                checkStatuses.add(CheckStatus.WAIT_AFTER_SALE);
                data.put(userOrder.getOrderClient().name(), checkStatuses);
            }
        }

        if (data.isEmpty()) {
            return null;
        }
        Map<String,String> clientResult = new HashMap<>();
        data.forEach((k, v) -> {
            StringBuffer result = new StringBuffer("");
            if (v.contains(CheckStatus.WAIT_PAY)){
                result.append("待支付");
            } if (v.contains(CheckStatus.WAIT_CONFIRM)){
                if (result.length() > 0) {
                    result.append("/");
                }
                result.append("未确认收货");
            } if (v.contains(CheckStatus.WAIT_AFTER_SALE)){
                if (result.length() > 0) {
                    result.append("/");
                }
                result.append("售后处理中");
            }
            if (result.length() > 0) {
                clientResult.put(k,result.toString());
            }
        });
        return clientResult;
    }

    /**
     * 账号注销，群聊处理
     * 学生：退群，删除好友关系
     * 老师：非机构群 群主，注销群，删除好友
     */
    @Override
    public void logoffQuitImGroup(String phone) {
        SysUser sysUser = this.getDao().findUserByPhone(phone);
        if (sysUser == null) {
            return;
        }
        Long userId = sysUser.getId();
        Student student = studentService.getById(userId);
        if (student != null) {
            List<ImGroupMember> groupMembers = imGroupMemberService.lambdaQuery()
                    .eq(ImGroupMember::getUserId, sysUser.getId())
                    .eq(ImGroupMember::getGroupRoleType, EImGroupMemberRoleType.Member)
                    .list();
            List<String> groupIdList = groupMembers.stream().map(ImGroupMember::getGroupId).collect(Collectors.toList());
            // 退群
            for (String groupId : groupIdList) {
                try {
                    imGroupService.quit(groupId, userId, ClientEnum.STUDENT, true);
                } catch (Exception e) {
                    log.error("学生注销退群失败->学生：" + userId + "," + e.getMessage());
                }
            }
            // 删除好友
            imUserFriendService.lambdaUpdate()
                    .eq(ImUserFriend::getUserId, userId)
                    .eq(ImUserFriend::getClientType, EClientType.STUDENT)
                    .remove();
            imUserFriendService.lambdaUpdate()
                    .eq(ImUserFriend::getFriendId, userId)
                    .eq(ImUserFriend::getFriendType, EClientType.STUDENT)
                    .remove();

            // 注销三方im
//            imGroupCoreService.accountDelete(Lists.newArrayList(imGroupCoreService.getImUserId(userId, ClientEnum.STUDENT)));
        }


        Teacher teacher = teacherService.getById(sysUser.getId());
        if (teacher != null) {
            List<ImGroupMember> groupMembers = imGroupMemberService.lambdaQuery()
                    .eq(ImGroupMember::getUserId, sysUser.getId())
                    .eq(ImGroupMember::getGroupRoleType, EImGroupMemberRoleType.Owner)
                    .list();
            List<String> groupIdList = groupMembers.stream().map(ImGroupMember::getGroupId).collect(Collectors.toList());
            if (groupIdList.isEmpty()) {
                return;
            }
            Collection<ImGroup> imGroups = imGroupService.listByIds(groupIdList);
            List<String> groupIds = imGroups.stream().filter(next -> ImGroupType.FAN.equals(next.getType()) || ImGroupType.COURSE.equals(next.getType()))
                    .map(ImGroup::getId).collect(Collectors.toList());

            for (String groupId : groupIds) {
                try {
                    imGroupService.dismiss(groupId);
                } catch (Exception e) {
                    log.error("群解散失败:" + groupId);
                }
            }
            // 删除好友
            imUserFriendService.lambdaUpdate()
                    .eq(ImUserFriend::getUserId, userId)
                    .eq(ImUserFriend::getClientType, EClientType.TEACHER)
                    .remove();
            imUserFriendService.lambdaUpdate()
                    .eq(ImUserFriend::getFriendId, userId)
                    .eq(ImUserFriend::getFriendType, EClientType.TEACHER)
                    .remove();
            // 注销三方im
//            imGroupCoreService.accountDelete(Lists.newArrayList(imGroupCoreService.getImUserId(userId, ClientEnum.TEACHER)));
        }
    }
    public EClientType getClientType(String jpushType){
        if(StringUtils.isEmpty(jpushType)){
            return null;
        }else if(jpushType.contains("STUDENT")){
            return EClientType.STUDENT;
        }else if(jpushType.contains("TEACHER")){
            return EClientType.TEACHER;
        }else {
            return EClientType.BACKEND;
        }
    }
}