package com.cpop.oam.business.service.impl;

import com.cpop.common.utils.StringUtils;
import com.cpop.core.base.enums.InitRoleEnum;
import com.cpop.core.base.enums.UserType;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.table.SysUser;
import com.cpop.core.mapper.CoreMapper;
import com.cpop.core.utils.*;
import com.cpop.core.utils.uuid.IdUtils;
import com.cpop.oam.business.bo.StaffBo;
import com.cpop.oam.business.entity.Dept;
import com.cpop.oam.business.entity.Staff;
import com.cpop.oam.business.entity.StaffMidDept;
import com.cpop.oam.business.service.DeptService;
import com.cpop.oam.business.service.OamWxCpService;
import com.cpop.oam.business.service.StaffMidDeptService;
import com.cpop.oam.business.service.StaffService;
import com.cpop.oam.business.vo.WxCpLoginVo;
import com.cpop.oam.framework.config.wxCp.WxCpConfiguration;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.row.RowUtil;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.api.WxCpOAuth2Service;
import me.chanjar.weixin.cp.api.WxCpService;
import me.chanjar.weixin.cp.bean.WxCpDepart;
import me.chanjar.weixin.cp.bean.WxCpOauth2UserInfo;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.bean.WxCpUserDetail;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
import static com.cpop.oam.business.entity.table.DeptTableDef.DEPT;
import static com.cpop.oam.business.entity.table.StaffTableDef.STAFF;

/**
 * @author DB
 * @createTime 2023/11/17 9:42
 * @description Oam暴露的企业微信接口
 */
@Slf4j
@Service("oamWxCpService")
public class OamWxCpServiceImpl implements OamWxCpService {

    /**
     * @descriptions 同步企业微信部门
     * @author DB
     * @date 2023/11/15 16:56
     * @return: void
     */
    @Override
    public void syncWxCpDept() {
        // 企业微信互通应用
        WxCpService cpService = WxCpConfiguration.getCpService(1000024);
        try {
            // 获取所有数据
            List<WxCpDepart> list = cpService.getDepartmentService().list(null);
            // 过滤出最顶级部门
            WxCpDepart wxCpDepart =
                list.stream().filter(item -> item.getParentId() == 0).collect(Collectors.toList()).get(0);
            // 先存
            Dept dept = new Dept();
            dept.setWxCpId(wxCpDepart.getId())
                .setWxCpParentId(wxCpDepart.getParentId())
                .setOrderNo(wxCpDepart.getOrder().intValue())
                .setName(wxCpDepart.getName());
            if (wxCpDepart.getDepartmentLeader().length > 0) {
                dept.setLeader(wxCpDepart.getDepartmentLeader()[0]);
            }
            SpringUtils.getBean(DeptService.class).save(dept);
            // 递归保存余下部门
            List<WxCpDepart> filterWxDeptList =
                list.stream().filter(item -> item.getParentId() != 0).collect(Collectors.toList());
            recursionSonDept(filterWxDeptList, dept);
        } catch (WxErrorException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * @descriptions 递归保存子部门
     * @author DB
     * @date 2023/11/16 16:06
     * @param wxCpDepartList 部门id
     * @param parentDept 父部门
     * @return: void
     */
    private void recursionSonDept(List<WxCpDepart> wxCpDepartList, Dept parentDept) {
        List<Dept> deptList = new ArrayList<Dept>();
        Iterator<WxCpDepart> iterator = wxCpDepartList.iterator();
        while (iterator.hasNext()) {
            WxCpDepart next = iterator.next();
            if (next.getParentId().equals(parentDept.getWxCpId())) {
                // 先存
                Dept dept = new Dept();
                dept.setWxCpId(next.getId())
                    .setWxCpParentId(next.getParentId())
                    .setOrderNo(next.getOrder().intValue())
                    .setParentId(parentDept.getId())
                    .setName(next.getName());
                deptList.add(dept);
                iterator.remove();
            }
        }
        // 当子部门不为空的时候保存部门
        if (!deptList.isEmpty()) {
            SpringUtils.getBean(DeptService.class).saveBatch(deptList);
            deptList.forEach(item -> {
                recursionSonDept(wxCpDepartList, item);
            });
        }
    }

    /**
     * @descriptions 同步企业微信员工
     * @author DB
     * @date 2023/11/16 17:04
     * @return: void
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncWxCpStaff() {
        WxCpService cpService = WxCpConfiguration.getCpService(1000024);
        try {
            List<WxCpUser> wxCpUsers = cpService.getUserService().listByDepartment(1L, true, 0);
            if (!wxCpUsers.isEmpty()) {
                // 批量插入用户
                Map<SysUser, WxCpUser> userWxCpUserMap = new HashMap<>();
                wxCpUsers.forEach(item -> {
                    SysUser sysUser = new SysUser();
                    sysUser.setId(IdUtils.fastSimpleUUID())
                        .setStatus(item.getStatus() == 1)
                        .setUserType(UserType.OAM_USER.toString())
                        .setCreateUserId("1");
                    sysUser.setUpdateUserId("1");
                    userWxCpUserMap.put(sysUser, item);
                });
                Db.executeBatch(userWxCpUserMap.keySet(), CoreMapper.class, CoreMapper::insertSysUser);
                List<Staff> staffList = new ArrayList<>();
                // 批量创建用户
                userWxCpUserMap.forEach((key, value) -> {
                    Staff staff = new Staff();
                    staff.setName(value.getName()).setUserId(key.getId()).setWxCpUserId(value.getUserId());
                    staffList.add(staff);
                });
                SpringUtils.getBean(StaffService.class).saveBatch(staffList);
                // 获取所有部门信息
                List<Dept> deptList =
                    SpringUtils.getBean(DeptService.class).queryChain().where(DEPT.WX_CP_ID.isNotNull()).list();
                // 部门id映射
                Map<Long, String> deptMap = deptList.stream().collect(Collectors.toMap(Dept::getWxCpId, Dept::getId));
                Map<String, String> userIdToStaffIdMap =
                    staffList.stream().collect(Collectors.toMap(Staff::getUserId, Staff::getId));
                List<StaffMidDept> staffMidDeptList = new ArrayList<>();
                // 批量创建用户
                userWxCpUserMap.forEach((key, value) -> {
                    for (Long wxDeptId : value.getDepartIds()) {
                        StaffMidDept staffMidDept = new StaffMidDept();
                        staffMidDept.setStaffId(userIdToStaffIdMap.get(key.getId())).setDeptId(deptMap.get(wxDeptId));
                        staffMidDeptList.add(staffMidDept);
                    }
                });
                SpringUtils.getBean(StaffMidDeptService.class).saveBatch(staffMidDeptList);
            }
        } catch (WxErrorException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * @descriptions 根据code换取用户信息
     * @author DB
     * @date 2023/11/20 18:19
     * @param code code
     * @return: void
     */
    @Override
    public WxCpLoginVo loginUserInfoByCode(HttpServletRequest httpServletRequest, String code) {
        WxCpService cpService = WxCpConfiguration.getCpService(1000024);
        try {
            // 获取用户信息
            WxCpOAuth2Service oauth2Service = cpService.getOauth2Service();
            // 此处只能获取企业微信的userId
            WxCpOauth2UserInfo userInfo = oauth2Service.getUserInfo(1000024, code);
            String wxCpUserId = userInfo.getUserId();
            // 查询用户信息
            Row row = Db.selectOneByQuery("cp_sys_user",
                QueryWrapper.create()
                    .select(SYS_USER.ALL_COLUMNS)
                    .leftJoin(STAFF)
                    .on(STAFF.USER_ID.eq(SYS_USER.ID))
                    .where(STAFF.WX_CP_USER_ID.eq(wxCpUserId)));
            if (null == row) {
                throw new ServiceException("请先在企微上的Oam应用中进行注册");
            }
            SysUser sysUser = RowUtil.toEntity(row, SysUser.class);
            return new WxCpLoginVo(sysUser.getUserName(), sysUser.getRsaPassword());
        } catch (WxErrorException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * @descriptions 企微的o2认证可查询用户敏感信息
     * @author DB
     * @date 2023/11/21 15:31
     * @param agentId 应用id
     * @param code 授权码
     * @return: void
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registerCode(Integer agentId, String code) {
        WxCpService cpService = WxCpConfiguration.getCpService(agentId);
        // 获取用户信息
        WxCpOAuth2Service oauth2Service = cpService.getOauth2Service();
        try {
            WxCpOauth2UserInfo userInfo = oauth2Service.getUserInfo(agentId, code);
            // 获取用户敏感信息
            WxCpUserDetail userDetail = oauth2Service.getUserDetail(userInfo.getUserTicket());
            // 此时可以获取敏感信息
            if (StringUtils.isBlank(userDetail.getMobile())) {
                throw new ServiceException("请重新扫码并授权敏感信息!");
            }
            // 读取员工信息
            StaffService staffService = SpringUtils.getBean(StaffService.class);
            long count = staffService.queryChain().where(STAFF.WX_CP_USER_ID.eq(userDetail.getUserId())).count();
            if (count > 0) {
                throw new ServiceException("您已通过注册,请扫码或直接通过用户名密码登陆!");
            }
            // 获取部门信息
            WxCpUser wxCpUser = cpService.getUserService().getById(userInfo.getUserId());
            List<Dept> deptList = SpringUtils.getBean(DeptService.class).list();
            Map<Long, Dept> wxCpDeptMap = deptList.stream().collect(Collectors.toMap(Dept::getWxCpId, item -> item));
            // 创建员工
            StaffBo staffBo = new StaffBo();
            String deptIds = "";
            // 调整部门数据
            for (Long departId : wxCpUser.getDepartIds()) {
                Dept dept = wxCpDeptMap.get(departId);
                if (dept != null) {
                    if (StringUtils.isBlank(deptIds)) {
                        deptIds = deptIds + dept.getId();
                    } else {
                        deptIds = deptIds + "," + dept.getId();
                    }
                }
            }
            String encrypt = SpringUtils.getBean(RsaUtils.class).encrypt(userDetail.getMobile());
            // 读取用户通用信息
            staffBo.setUserName(userDetail.getMobile())
                .setName(wxCpUser.getName())
                .setNickName(wxCpUser.getAlias())
                .setAvatar(userDetail.getAvatar())
                .setEmail(userDetail.getBizMail())
                .setPhoneNumber(userDetail.getMobile())
                .setSex(!StringUtils.equals(userDetail.getGender(), "1"))
                .setStatus(true)
                .setStaffType(StringUtils.equals(wxCpUser.getMainDepartment(), "5") ? 0 : 1)
                .setWxCpUserId(wxCpUser.getUserId())
                // 密码默认为手机号
                .setPassword(encrypt)
                // 设置部门
                .setDeptId(deptIds)
                // 区分技术员工和运营员工
                .setRoleId(StringUtils.equals(wxCpUser.getMainDepartment(), "5")
                    ? InitRoleEnum.WX_CP_INIT_TECHNOLOGY_ROLE.getId()
                    : InitRoleEnum.WX_CP_INIT_OPERATION_ROLE.getId());
            // 保存员工
            staffService.insertStaff(staffBo);
        } catch (WxErrorException e) {
            throw new ServiceException(e.getMessage());
        }
    }
}
