package com.fjhx.dingding.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.dingtalk.api.response.OapiV2DepartmentListsubResponse;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.dingding.entity.dto.GetUserTokenDto;
import com.fjhx.dingding.service.DingService;
import com.fjhx.dingding.utils.DingUtil;
import com.fjhx.tenant.entity.tenant.po.TenantInfo;
import com.fjhx.tenant.service.tenant.impl.TenantInfoServiceImpl;
import com.ruoyi.common.constant.StatusConstant;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import com.ruoyi.framework.web.service.SysPermissionService;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysRoleService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.utils.ConfigUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DingServiceImpl implements DingService {

    @Autowired
    private TenantInfoServiceImpl tenantInfoService;

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Autowired
    private TransactionDefinition transactionDefinition;

    @Autowired
    private ISysDeptService sysDeptService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private ISysRoleService sysRoleService;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private SysPermissionService permissionService;

    /**
     * https://open.dingtalk.com/document/isvapp/data-formats
     */
    @Override
    public void pushHigh(JSONObject callBackContent) {
        JSONArray bizData = callBackContent.getJSONArray("bizData");

        for (JSONObject jsonObject : bizData.toJavaList(JSONObject.class)) {
            switch (jsonObject.getInteger("biz_type")) {
                case 2:
                    saveSuiteTicketInfo(jsonObject);
                    break;
                case 4:
                    corpAuthorization(jsonObject);
                    break;
            }
        }

    }

    @DSTransactional
    @Override
    public String getUserToken(GetUserTokenDto dto) {
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        OapiV2UserGetuserinfoResponse.UserGetByCodeResponse userInfo = DingUtil.getUserInfo(dto.getCorpId(), dto.getCode());
        String userid = userInfo.getUserid();
        SysUser sysUser = sysUserService.getOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getDdUserId, userid));
        if (sysUser == null) {

            TenantInfo tenantInfo = tenantInfoService.getOne(Wrappers.<TenantInfo>lambdaQuery()
                    .eq(TenantInfo::getCorpid, dto.getCorpId()));

            if (tenantInfo == null) {
                throw new ServiceException("未知corpId");
            }

            sysUser = new SysUser();
            OapiV2UserGetResponse.UserGetResponse userDetail = DingUtil.getUserDetail(dto.getCorpId(), userid);
            List<Long> deptIdList = userDetail.getDeptIdList();
            if (deptIdList.size() > 0) {
                Long deptId = deptIdList.get(0);
                SysDept sysDept = sysDeptService.getOne(Wrappers.<SysDept>lambdaQuery().eq(SysDept::getDingDeptId, deptId));
                if (sysDept != null) {
                    sysUser.setDeptId(sysDept.getDeptId());
                }
            }
            sysUser.setDdUserId(userid);
            sysUser.setTenantId(tenantInfo.getTenantId());
            sysUser.setUserName("admin");
            sysUser.setNickName(userInfo.getName());
            sysUser.setPassword(SecurityUtils.encryptPassword(RandomUtil.randomString(6)));
            sysUser.setStatus("0");
            sysUser.setCreateBy("admin");
            sysUser.setCreateTime(new Date());
            sysUserService.save(sysUser);

            SysRole sysRole = sysRoleService.getOne(Wrappers.<SysRole>lambdaQuery()
                    .eq(SysRole::getTenantId, tenantInfo.getTenantId())
                    .eq(SysRole::getRoleKey, "admin")
            );

            // 角色用户id关联
            sysRoleService.insertAuthUsers(sysRole.getRoleId(), new Long[]{sysUser.getUserId()});
        }

        SysUser user = sysUserService.selectUserByUserName(sysUser.getTenantId(), sysUser.getUserName());
        LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
        recordLoginInfo(sysUser.getUserId());
        String token = tokenService.createToken(loginUser);

        DynamicDataSourceContextHolder.poll();
        return token;
    }

    /**
     * 保存 suite_ticket
     */
    private void saveSuiteTicketInfo(JSONObject bizData) {
        String suiteTicket = bizData.getJSONObject("biz_data").getString("suiteTicket");
        ConfigUtil.set("dd_suite_ticket", suiteTicket);
    }

    /**
     * 企业授权
     * <p>
     * https://open.dingtalk.com/document/isvapp/obtains-the-authorization-information-after-the-enterprise-activates-the-application
     */
    private void corpAuthorization(JSONObject bizData) {

        String itemBizDataStr = bizData.getString("biz_data");
        JSONObject jsonObject = JSON.parseObject(itemBizDataStr);

        String syncAction = jsonObject.getString("syncAction");

        switch (syncAction) {

            // 企业授权
            case "org_suite_auth":
                orgSuiteAuth(jsonObject);
                break;

            // 企业变更授权范围
            case "org_suite_change":

                break;

            // 表示企业解除授权
            case "org_suite_relieve":
                DynamicDataSourceContextHolder.push(SourceConstant.BASE);
                // 企业id
                String corpid = bizData.getString("corp_id");

                // 禁用租户
                tenantInfoService.update(Wrappers.<TenantInfo>lambdaUpdate()
                        .eq(TenantInfo::getCorpid, corpid)
                        .set(TenantInfo::getStatus, StatusConstant.DISABLE)
                );
                DynamicDataSourceContextHolder.poll();
                break;
        }

    }

    /**
     * 企业授权
     */
    private void orgSuiteAuth(JSONObject bizData) {
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);

        JSONObject authCorpInfo = bizData.getJSONObject("auth_corp_info");

        // 企业id
        String corpid = authCorpInfo.getString("corpid");
        // 企业名称
        String corpName = authCorpInfo.getString("corp_name");
        String userId = bizData.getJSONObject("auth_user_info").getString("userId");

        // 企业id存在则跳过
        TenantInfo tempTenantInfo = tenantInfoService.getOne(q -> q.eq(TenantInfo::getCorpid, corpid));
        if (tempTenantInfo != null) {
            if (ObjectUtil.equals(tempTenantInfo.getStatus(), StatusConstant.DISABLE)) {
                tempTenantInfo.setStatus(StatusConstant.ENABLE);
                tenantInfoService.updateById(tempTenantInfo);
            }
            return;
        }

        // 获取tenantId
        String firstLetter = PinyinUtil.getFirstLetter(corpName, "");
        String tenantId = "dd-" + firstLetter;

        List<TenantInfo> list = tenantInfoService.list(q -> q
                .likeRight(TenantInfo::getTenantId, "dd-" + firstLetter));

        List<String> tenantIdList = list.stream().map(TenantInfo::getTenantId).collect(Collectors.toList());

        if (list.size() > 0) {
            String tempTenantId;
            do {
                tempTenantId = tenantId + "-" + RandomUtil.randomString(3);
            } while (!tenantIdList.contains(tempTenantId));
            tenantId = tempTenantId;
        }

        // 创建租户
        TenantInfo tenantInfo = new TenantInfo();
        tenantInfo.setTenantId(tenantId);
        tenantInfo.setEnterpriseName(corpName);
        tenantInfo.setStatus(StatusConstant.ENABLE);
        tenantInfo.setFlowStatus(2);
        tenantInfo.setCorpid(corpid);

        // 创建部门
        List<SysDept> deptList = new ArrayList<>();
        addDeptList(corpid, deptList, tenantId, 1L, 0L);

        OapiV2UserGetResponse.UserGetResponse userDetail = DingUtil.getUserDetail(corpid, userId);

        // 创建用户
        SysUser sysUser = new SysUser();
        List<Long> deptIdList = userDetail.getDeptIdList();
        if (deptIdList.size() > 0) {
            Map<Long, Long> collect = deptList.stream().collect(Collectors.toMap(SysDept::getDingDeptId, SysDept::getDeptId));
            sysUser.setDeptId(collect.get(deptIdList.get(0)));
        }
        sysUser.setTenantId(tenantId);
        sysUser.setUserType(2);
        sysUser.setJobNumber(userDetail.getJobNumber());
        sysUser.setUserName("admin");
        sysUser.setNickName(corpName + "管理员");
        sysUser.setPassword(SecurityUtils.encryptPassword(RandomUtil.randomString(6)));
        sysUser.setStatus("0");
        sysUser.setCreateTime(new Date());
        sysUser.setUpdateTime(new Date());
        sysUser.setDdUserId(userId);

        SysRole sysRole = new SysRole();
        sysRole.setRoleName("管理员");
        sysRole.setRoleKey("admin");
        sysRole.setRoleSort(1);
        sysRole.setDataScope("1");
        sysRole.setStatus("0");
        sysRole.setTenantId(tenantId);
        sysRole.setCreateTime(new Date());
        sysRole.setUpdateTime(new Date());

        log.info("钉钉回调创建租户，tenantInfo：{}", JSON.toJSONString(tenantInfo));
        log.info("钉钉回调创建部门，deptList：{}", JSON.toJSONString(deptList));
        log.info("钉钉回调创建用户，sysUser：{}", JSON.toJSONString(sysUser));
        log.info("钉钉回调创建角色，sysRole：{}", JSON.toJSONString(sysRole));

        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(transactionDefinition);
        try {
            // 保存租户
            tenantInfoService.save(tenantInfo);
            // 保存部门
            sysDeptService.saveBatch(deptList);
            // 保存用户
            sysUserService.save(sysUser);
            // 保存角色
            sysRoleService.save(sysRole);
            // 角色用户id关联
            sysRoleService.insertAuthUsers(sysRole.getRoleId(), new Long[]{sysUser.getUserId()});
            // 提交事务
            platformTransactionManager.commit(transactionStatus);

            DynamicDataSourceContextHolder.poll();
        } catch (Exception e) {
            // 回滚事务
            platformTransactionManager.rollback(transactionStatus);
            throw new ServiceException("保存数据失败");
        }
    }

    /**
     * 添加部门列表
     */
    private void addDeptList(String corpid, List<SysDept> deptList, String tenantId, Long dingParentId, Long myParentId) {

        List<OapiV2DepartmentListsubResponse.DeptBaseResponse> tempDeptList = DingUtil.getDeptList(corpid, dingParentId);

        if (ObjectUtil.isEmpty(tempDeptList)) {
            return;
        }

        for (OapiV2DepartmentListsubResponse.DeptBaseResponse deptBaseResponse : tempDeptList) {
            SysDept sysDept = new SysDept();
            sysDept.setDeptId(IdWorker.getId());
            sysDept.setParentId(myParentId);
            sysDept.setDeptName(deptBaseResponse.getName());
            sysDept.setOrderNum(1);
            sysDept.setStatus("0");
            sysDept.setType(0);
            sysDept.setTenantId(tenantId);
            sysDept.setCreateTime(new Date());
            sysDept.setDingDeptId(deptBaseResponse.getDeptId());

            deptList.add(sysDept);

            addDeptList(corpid, deptList, tenantId, deptBaseResponse.getDeptId(), sysDept.getDeptId());
        }
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUserService.updateUserProfile(sysUser);
    }

}
