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

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.auth.api.client.SysUserFeignService;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.biz.dal.dao.SubjectDao;
import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
import com.yonge.cooleshow.biz.dal.entity.*;
import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
import com.yonge.cooleshow.biz.dal.enums.ImGroupType;
import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
import com.yonge.cooleshow.biz.dal.mapper.SysAreaMapper;
import com.yonge.cooleshow.biz.dal.mapper.TenantGroupMapper;
import com.yonge.cooleshow.biz.dal.mapper.TenantUnbindRecordMapper;
import com.yonge.cooleshow.biz.dal.mapper.UserTenantBindRecordMapper;
import com.yonge.cooleshow.biz.dal.service.*;
import com.yonge.cooleshow.biz.dal.wrapper.TenantUnbindRecordWrapper;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.cooleshow.common.enums.ESettlementFrom;
import com.yonge.cooleshow.common.enums.ETenantUnBindAuditStatus;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 机构解绑申请记录
 * 2023-07-21 17:32:49
 */
@Slf4j
@Service
public class TenantUnbindRecordServiceImpl extends ServiceImpl<TenantUnbindRecordMapper, TenantUnbindRecord> implements TenantUnbindRecordService {


    @Autowired
    private TeacherDao teacherDao;

    @Autowired
    private SubjectDao subjectDao;

    @Autowired
    private TenantUnbindRecordService tenantUnbindRecordService;

    @Autowired
    private SysUserFeignService sysUserFeignService;

    @Autowired
    private SysConfigService sysConfigService;

    @Autowired
    private SysAreaMapper sysAreaMapper;

    @Autowired
    private TenantInfoService tenantInfoService;

    @Autowired
    private SysMessageService sysMessageService;

    @Autowired
    private TenantUnbindHistoryService tenantUnbindHistoryService;

    @Autowired
    private ImGroupService imGroupService;

    @Autowired
    private UnbindAuthUserService unbindAuthUserService;

    @Autowired
    private ImUserFriendService imUserFriendService;

    @Autowired
    private TenantGroupMapper tenantGroupMapper;

    @Autowired
    private ImGroupMemberService imGroupMemberService;

    @Autowired
    private UserTenantBindRecordMapper userTenantBindRecordMapper;

    /**
     * @param id 详情ID
     * @return TenantUnbindRecord
     */
    @Override
    public TenantUnbindRecord detail(Long id) {

        return baseMapper.selectById(id);
    }

    /**
     * 分页查询
     *
     * @param page  IPage<TenantUnbindRecord>
     * @param query TenantUnbindRecordWrapper.TenantUnbindRecordQuery
     * @return IPage<TenantUnbindRecord>
     */
    @Override
    public IPage<TenantUnbindRecordWrapper.TenantUnbindRecord> selectPage(
            IPage<TenantUnbindRecordWrapper.TenantUnbindRecord> page,
            TenantUnbindRecordWrapper.TenantUnbindRecordQuery query) {

        List<TenantUnbindRecordWrapper.TenantUnbindRecord> records = baseMapper.selectPage(page, query);
        if (records.isEmpty()) {
            return page.setRecords(records);
        }

        List<Integer> areaCodeList = records.stream().map(next -> {
            HashSet<Integer> areaCodes = new HashSet<>();
            areaCodes.add(next.getProvinceCode());
            areaCodes.add(next.getCityCode());
            areaCodes.add(next.getRegionCode());
            return areaCodes;
        }).flatMap(Collection::stream).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (!areaCodeList.isEmpty()) {
            QueryWrapper<SysArea> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda().in(SysArea::getCode, areaCodeList);

            Map<Integer, String> codeNameMap = sysAreaMapper.selectList(queryWrapper)
                    .stream().collect(Collectors.toMap(SysArea::getCode, SysArea::getName));

            records.forEach(next -> {
                next.setProvinceName(codeNameMap.getOrDefault(next.getProvinceCode(), ""));
                next.setCityName(codeNameMap.getOrDefault(next.getCityCode(), ""));
                next.setRegionName(codeNameMap.getOrDefault(next.getRegionCode(), ""));
            });
        }

//        List<Long> teacherIdList = records.stream().map(TenantUnbindRecordWrapper.TenantUnbindRecord::getUserId)
//                .collect(Collectors.toList());

//        QueryWrapper<Teacher> objectQueryWrapper = new QueryWrapper<>();
//        objectQueryWrapper.lambda().in(Teacher::getUserId, teacherIdList);
//        List<Teacher> teachers = teacherDao.selectList(objectQueryWrapper);


//        List<Long> subjectIdList = teachers.stream().filter(next -> StringUtils.isNotEmpty(next.getSubjectId()))
//                .map(next -> Arrays.stream(next.getSubjectId().split(",")).map(Long::valueOf).collect(Collectors
//                .toList()))
//                .flatMap(Collection::stream).collect(Collectors.toList());
//
//        Map<Long, String> userIdSubjectNameMap = new HashMap<>();
//        Map<Long, String> userIdSubjectIdMap = new HashMap<>();
//        if (!subjectIdList.isEmpty()) {
//            List<Subject> subjectList = subjectDao.findBySubjectIds(subjectIdList);
//            Map<Long, String> idNameMap = subjectList.stream().collect(Collectors.toMap(Subject::getId,
//                    Subject::getName));
//
//            for (Teacher user : teachers) {
//                String subjectId = user.getSubjectId();
//                if (StringUtils.isEmpty(subjectId)) {
//                    continue;
//                }
//                userIdSubjectIdMap.put(user.getUserId(), subjectId);
//                List<String> names = Arrays.stream(subjectId.split(",")).map(next ->
//                        idNameMap.getOrDefault(Long.valueOf(next), "")).collect(Collectors.toList());
//                userIdSubjectNameMap.put(user.getUserId(), String.join(",", names));
//            }
//        }
//
//        for (TenantUnbindRecordWrapper.TenantUnbindRecord next : records) {
//            next.setSubjectId(userIdSubjectIdMap.getOrDefault(next.getUserId(), ""));
//            next.setSubjectName(userIdSubjectNameMap.getOrDefault(next.getUserId(), ""));
//        }
        return page.setRecords(records);
    }

    /**
     * 添加
     *
     * @param tenantUnbindRecord TenantUnbindRecordWrapper.TenantUnbindRecord
     * @return Boolean
     */
    @Override
    public Boolean add(TenantUnbindRecordWrapper.TenantUnbindRecord tenantUnbindRecord) {

        return this.save(JSON.parseObject(tenantUnbindRecord.jsonString(), TenantUnbindRecord.class));
    }

    /**
     * 更新
     *
     * @param tenantUnbindRecord TenantUnbindRecordWrapper.TenantUnbindRecord
     * @return Boolean
     */
    @Override
    public Boolean update(TenantUnbindRecordWrapper.TenantUnbindRecord tenantUnbindRecord) {

        return this.updateById(JSON.parseObject(tenantUnbindRecord.jsonString(), TenantUnbindRecord.class));
    }

    /**
     * 机构用户解绑审核
     *
     * @param audio        审核信息
     * @param verifyUserId 审核人
     * @param intervene    是否平台介入审核   true：后台审核，false:机构管理员
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void tenantUserUnbindAudit(TenantUnbindRecordWrapper.Audio audio, Long verifyUserId, Boolean intervene) {

        TenantUnbindRecord unbindRecord = tenantUnbindRecordService.getById(audio.getId());
        if (unbindRecord == null || !ETenantUnBindAuditStatus.DOING.equals(unbindRecord.getStatus())) {
            throw new BizException("审核记录不存在");
        }
        Teacher teacher = teacherDao.selectById(unbindRecord.getUserId());

        this.lambdaUpdate()
                .set(TenantUnbindRecord::getStatus, Boolean.TRUE.equals(audio.getStatus()) ?
                        ETenantUnBindAuditStatus.PASS : ETenantUnBindAuditStatus.UNPASS)
                .set(TenantUnbindRecord::getReason, audio.getReason())
                .set(TenantUnbindRecord::getInterveneTime, Boolean.TRUE.equals(intervene) ? new Date() : null)
                .set(TenantUnbindRecord::getVerifyUserId, verifyUserId)
                .eq(TenantUnbindRecord::getId, audio.getId())
                .eq(TenantUnbindRecord::getStatus, ETenantUnBindAuditStatus.DOING)
                .update();
        if (Boolean.TRUE.equals(audio.getStatus())) {
            // 判断是否存在机构小组群主身份
            QueryWrapper<TenantGroup> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda()
                    .eq(TenantGroup::getTenantId, teacher.getTenantId())
                    .eq(TenantGroup::getAdminId, teacher.getUserId());
            Integer count = tenantGroupMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BizException("该老师存在机构小组负责人身份，请先更换老师或者退出小组");
            }

            Long tenantId = teacher.getTenantId();
            if (tenantId != -1L) {
                // 解散机构群
                List<String> imGroupIds = imGroupMemberService.lambdaQuery()
                        .eq(ImGroupMember::getUserId, unbindRecord.getUserId())
                        .eq(ImGroupMember::getIsAdmin, true)
                        .eq(ImGroupMember::getRoleType, ImGroupMemberRoleType.TEACHER)
                        .list().stream().map(ImGroupMember::getGroupId).distinct().collect(Collectors.toList());
                if (!imGroupIds.isEmpty()) {
                    List<ImGroup> imGroups = imGroupService.lambdaQuery()
                            .in(ImGroup::getId, imGroupIds)
                            .eq(ImGroup::getType, ImGroupType.ORG)
                            .list();
                    imGroups.forEach(next -> {
                        try {
                            imGroupService.dismiss(next.getId());
                        } catch (Exception e) {
                            log.error("老师修改机构，解散机构群失败：{}", e.getMessage());
                        }
                    });
                }
                imUserFriendService.delStudentFriendByTenantId(tenantId, unbindRecord.getUserId(),
                        ClientEnum.TEACHER.getCode());
            }
            teacherDao.update(null, Wrappers.<Teacher>lambdaUpdate()
                    .eq(Teacher::getUserId, unbindRecord.getUserId())
                    .set(ESettlementFrom.TENANT.equals(teacher.getSettlementFrom()), Teacher::getSettlementFrom,
                            ESettlementFrom.TEACHER)
                    .set(Teacher::getTenantId, -1L));

            UserTenantBindRecord bindRecord = new UserTenantBindRecord();
            bindRecord.setUserId(unbindRecord.getUserId());
            bindRecord.setUserType("TEACHER");
            bindRecord.setTenantId(tenantId);
            bindRecord.setBindStatus(false);
            bindRecord.setBindTime(new Date());
            userTenantBindRecordMapper.add(bindRecord);
        }

        // 添加历史记录
        TenantUnbindRecord newRecord = tenantUnbindRecordService.getById(audio.getId());
        TenantUnbindHistory history = JSON.parseObject(JSON.toJSONString(newRecord), TenantUnbindHistory.class);
        history.setId(null);
        tenantUnbindHistoryService.save(history);

        // 老师端发送消息
        CompletableFuture.runAsync(() -> sendTeacherUnBindMessage(audio, newRecord));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void unbindTenant(Long tenantId, Long verityUserId, TenantUnbindRecordWrapper.Unbind unbind) {
        Teacher teacher = teacherDao.selectById(unbind.getUserId());
        if (teacher == null || !teacher.getTenantId().equals(tenantId)) {
            throw new BizException("老师信息不存在");
        }
        teacher.setTenantId(-1L);
        teacherDao.updateById(teacher);
        // 如果有申请解绑，更新状态为关闭状态
        tenantUnbindRecordService.lambdaUpdate()
                .set(TenantUnbindRecord::getReason, unbind.getReason())
                .set(TenantUnbindRecord::getVerifyUserId, verityUserId)
                .set(TenantUnbindRecord::getStatus, ETenantUnBindAuditStatus.CLOSE)
                .eq(TenantUnbindRecord::getUserId, unbind.getUserId())
                .eq(TenantUnbindRecord::getUserType, "TEACHER")
                .eq(TenantUnbindRecord::getStatus, ETenantUnBindAuditStatus.DOING)
                .update();
    }

    /**
     * 定时发送平台审核短信 下午5点
     */
    @Override
    public void sendPlatformAuditMessage() {
        String configValue = sysConfigService.findConfigValue(SysConfigConstant.TENANT_USER_UNBIND_EXPIRE_TIME);
//        String unBindPhone = sysConfigService.findConfigValue(SysConfigConstant.TENANT_USER_UNBIND_PHONE);
        // 默认5天
        long expireTime = 5L;
        try {
            expireTime = Long.parseLong(configValue);
        } catch (Exception e) {
            expireTime = 5L;
        }
        // 查询机构超出5天未处理的解绑申请
        Integer count = tenantUnbindRecordService.lambdaQuery()
                .eq(TenantUnbindRecord::getStatus, ETenantUnBindAuditStatus.DOING)
                .le(TenantUnbindRecord::getCreateTime, DateUtil.offsetDay(new Date(), -(int) expireTime))
                .count();
        if (count == null || count == 0) {
            return;
        }
        // 查询平台审核人员 TODO 要根据地区区分，现在不用
        List<UnbindAuthUser> list = unbindAuthUserService.list();
        if(CollectionUtils.isEmpty(list)) {
            return;
        }
        long finalExpireTime = expireTime;
        CompletableFuture.runAsync(() -> {
            // 发送短信
            for (UnbindAuthUser unbindAuthUser : list) {
                SysUser sysUser = sysUserFeignService.queryUserById(unbindAuthUser.getUserId());
                if (sysUser == null) {
                    continue;
                }
                Map<Long, String> receivers = new HashMap<>();
                receivers.put(unbindAuthUser.getUserId(), sysUser.getPhone());
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
                        MessageTypeEnum.PLATFORM_AUDIT_UNBIND,
                        receivers, null, 0, null, ClientEnum.SYSTEM.getCode(), count, finalExpireTime);
            }

        });


    }

    private void sendTeacherUnBindMessage(TenantUnbindRecordWrapper.Audio audio, TenantUnbindRecord record) {
        TenantInfo tenantInfo = tenantInfoService.getById(record.getTenantId());
        if (tenantInfo == null) {
            log.error("机构入驻审核发送消息失败,机构信息不存在,机构id:{}", record.getTenantId());
            return;
        }
        //发送短信
        SysUser sysUser = sysUserFeignService.queryUserById(record.getUserId());
        Map<Long, String> receivers = new HashMap<>();
        receivers.put(record.getUserId(), sysUser.getPhone());
        if (Boolean.TRUE.equals(audio.getStatus())) {
            try {
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                        MessageTypeEnum.TEACHER_UNBIND_PASS,
                        receivers, null, 0, null, ClientEnum.TEACHER.getCode(), tenantInfo.getName());
            } catch (Exception e) {
                log.error("机构入驻审核极光消息推送异常");
            }
        } else {
            try {
                String serviceConfig = sysConfigService.findConfigValue(SysConfigConstant.CUSTOMER_SERVICE_PHONE);
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                        MessageTypeEnum.TEACHER_UNBIND_UNPASS,
                        receivers, null, 0, null, ClientEnum.TEACHER.getCode(), tenantInfo.getName(),
                        audio.getReason(), serviceConfig);
            } catch (Exception e) {
                log.error("机构入驻审核极光消息推送异常");
            }
        }
    }
}