package com.skr.mdm.api.company.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.skr.mdm.api.admin.service.AdminService;
import com.skr.mdm.api.company.service.CompanyService;
import com.skr.mdm.api.company.service.FunctionScopeService;
import com.skr.mdm.bean.qo.CompanyQO;
import com.skr.mdm.bean.qo.admin.AdminQO;
import com.skr.mdm.bean.vo.company.CompanyVO;
import com.skr.mdm.dao.*;
import com.skr.mdm.dto.LoginAdminDTO;
import com.skr.mdm.entity.*;
import com.skr.mdm.enums.DeleteStateEnum;
import com.skr.mdm.enums.ResultCodeEnum;
import com.skr.mdm.exception.ServiceException;
import com.skr.mdm.manager.oss.MinIoManager;
import com.skr.mdm.publish.MdmEventPublisher;
import com.skr.mdm.result.ResponseResult;
import com.skr.mdm.util.PageUtil;
import com.skr.mdm.util.SmUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

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

/**
 * @author nfq
 * @date 2020/9/16 10:44
 */
@Service
public class CompanyServiceImpl implements CompanyService {

    @Autowired
    private AuCompanyDao companyDao;
    @Autowired
    private SysFunctionScopePermissionDao functionScopePermissionDao;
    @Autowired
    private AuRoleDao roleDao;
    @Autowired
    private AuRolePermissionDao rolePermissionDao;
    @Autowired
    private AuAdminRoleDao adminRoleDao;
    @Autowired
    private AuDepartmentDao departmentDao;
    @Autowired
    private AdminService adminService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuAdminDao adminDao;
    @Autowired
    private FunctionScopeService functionScopeService;
    @Autowired
    private MinIoManager minIoManager;
    @Autowired
    private MdmEventPublisher mdmEventPublisher;
    @Autowired
    private DeviceEquipmentDao equipmentDao;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public ResponseResult addCompany(CompanyQO companyQO) {
        // 公司名称查重
        Long count = new LambdaQueryChainWrapper<>(companyDao)
                .eq(AuCompanyDO::getCompanyName, companyQO.getCompanyName())
                .count();
        if (count > 0) {
            return ResponseResult.failure(ResultCodeEnum.COMPANY_NAME_REPEAT);
        }
        Integer functionScopeId = companyQO.getFunctionScopeId();
        List<SysFunctionScopePermissionDO> functionScopePermissionDOList = new LambdaQueryChainWrapper<>(functionScopePermissionDao)
                .eq(SysFunctionScopePermissionDO::getFunctionScopeId, functionScopeId)
                .list();
        if (CollectionUtils.isEmpty(functionScopePermissionDOList)) {
            throw new ServiceException("该功能范围没有权限，请完善");
        }
        // 创建公司
        AuCompanyDO companyDO = new AuCompanyDO();
        BeanUtils.copyProperties(companyQO, companyDO);
        SM2 sm2 = SmUtils.sm2();
        // 授权数量 到期时间加密
        String encryptBcd = sm2.encryptBcd(String.valueOf(companyQO.getAllowUseNumber()), KeyType.PublicKey);
        String encryptExpirationTime = sm2.encryptBcd(String.valueOf(companyQO.getExpirationTime()), KeyType.PublicKey);
        companyDO.setAllowUseNumber(encryptBcd);
        companyDO.setExpirationTime(encryptExpirationTime);
        companyDO.setOperateTime(new Date());
        companyDO.setMaxDownloadNum(10);
        companyDao.insert(companyDO);
        // 添加角色
        List<Integer> permissionIdList = functionScopePermissionDOList
                .stream()
                .map(SysFunctionScopePermissionDO::getPermissionId)
                .collect(Collectors.toList());
        Integer roleId = saveRole(companyDO, permissionIdList);
        // 创建部门
        AuDepartmentDO departmentDO = saveDept(companyDO);
        // 创建超级管理员
        AdminQO adminQO = new AdminQO();
        BeanUtils.copyProperties(companyQO, adminQO);
        if (roleId != null) {
            adminQO.setRoleId(roleId);
            adminQO.setDepartmentIdList(ListUtil.toList(departmentDO.getId()));
            LoginAdminDTO loginAdminDTO = new LoginAdminDTO();
            loginAdminDTO.setCompanyId(companyDO.getId());
            ResponseResult addCheck = adminService.addCheck(adminQO.getEmail(), adminQO.getAdminName());
            if (addCheck != null) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return addCheck;
            }
            return adminService.addAdmin(adminQO, loginAdminDTO);
        }
        return ResponseResult.success();
    }

    private AuDepartmentDO saveDept(AuCompanyDO companyDO) {
        AuDepartmentDO departmentDO = AuDepartmentDO.builder()
                .departmentName(companyDO.getCompanyName())
                .isDefault(1)
                .parentId(0)
                .companyId(companyDO.getId())
                .build();
        departmentDao.insert(departmentDO);
        return departmentDO;
    }

    private Integer saveRole(AuCompanyDO companyDO, List<Integer> permissionIdList) {
        Integer roleId = null;
        AuRoleDO auRoleDO = new LambdaQueryChainWrapper<>(roleDao)
                .eq(AuRoleDO::getRoleName, "超级管理员")
                .eq(AuRoleDO::getCompanyId, companyDO.getId())
                .one();
        if (auRoleDO != null) {
            rolePermissionDao.insertBatch(auRoleDO.getId(), permissionIdList);
        } else {
            AuRoleDO roleDO = new AuRoleDO();
            roleDO.setRoleName("超级管理员");
            roleDO.setFunctionScopeId(companyDO.getFunctionScopeId());
            roleDO.setIsUsable(1);
            roleDO.setCompanyId(companyDO.getId());
            roleDO.setNote("");
            roleDO.setOperator("系统管理员");
            roleDO.setLevel(0);
            roleDao.insert(roleDO);
            roleId = roleDO.getId();
            rolePermissionDao.insertBatch(roleId, permissionIdList);
        }
        return roleId;
    }

    @Override
    public ResponseResult listCompany(Integer pageNum, Integer pageSize, Integer searchType, String searchValue) {
        PageHelper.startPage(pageNum, pageSize);
        List<CompanyVO> companyVOList = companyDao.listCompany(searchType, searchValue);
        if (CollectionUtils.isNotEmpty(companyVOList)) {
            SM2 sm2 = SmUtils.sm2();
            companyVOList.forEach(companyVO -> {
                if (StringUtils.isNotBlank(companyVO.getAllowUseNumber())) {
                    String allowUseNumber = StrUtil.utf8Str(sm2.decryptFromBcd(companyVO.getAllowUseNumber(), KeyType.PrivateKey));
                    companyVO.setAllowUseNumber(allowUseNumber);
                }
                if (StringUtils.isNotBlank(companyVO.getExpirationTime())) {
                    String expirationTime = StrUtil.utf8Str(sm2.decryptFromBcd(companyVO.getExpirationTime(), KeyType.PrivateKey));
                    companyVO.setExpirationTime(expirationTime);
                }
                companyVO.setAdminName(adminRoleDao.getSuperAdminName(companyVO.getId(), 0));
            });
        }
        PageInfo<CompanyVO> pageInfo = new PageInfo<>(companyVOList);
        return ResponseResult.success(PageUtil.getPageResult(pageInfo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateCompany(CompanyQO companyQO) {
        Long count = new LambdaQueryChainWrapper<>(companyDao)
                .eq(AuCompanyDO::getCompanyName, companyQO.getCompanyName())
                .ne(AuCompanyDO::getId, companyQO.getId())
                .count();
        if (count > 0) {
            return ResponseResult.failure(ResultCodeEnum.COMPANY_NAME_REPEAT);
        }
        Long countEquipment = new LambdaQueryChainWrapper<>(equipmentDao)
                .eq(DeviceEquipmentDO::getCompanyId, companyQO.getId())
                .eq(DeviceEquipmentDO::getIsDelete, DeleteStateEnum.NON_DELETE.getState())
                .count();
        if (countEquipment > companyQO.getAllowUseNumber()) {
            return ResponseResult.failure("授权数量不能低于公司已注册设备数量，请检查");
        }
        AuCompanyDO auCompanyDO = companyDao.selectById(companyQO.getId());
        AuCompanyDO companyDO = new AuCompanyDO();
        BeanUtils.copyProperties(companyQO, companyDO);
        SM2 sm2 = SmUtils.sm2();
        String encryptBcd = sm2.encryptBcd(String.valueOf(companyQO.getAllowUseNumber()), KeyType.PublicKey);
        String encryptExpirationTime = sm2.encryptBcd(String.valueOf(companyQO.getExpirationTime()), KeyType.PublicKey);
        companyDO.setAllowUseNumber(encryptBcd);
        companyDO.setExpirationTime(encryptExpirationTime);
        companyDO.setOperateTime(new Date());
        companyDao.updateById(companyDO);
        // sid可以为空
        if (companyDO.getSid() == null) {
            new LambdaUpdateChainWrapper<>(companyDao)
                    .set(AuCompanyDO::getSid, null)
                    .eq(AuCompanyDO::getId, companyDO.getId())
                    .update();
        }
        // 功能范围修改
        if (!companyQO.getFunctionScopeId().equals(auCompanyDO.getFunctionScopeId())) {
            // 修改公司超管权限
            Integer superRoleId = adminRoleDao.getSuperRoleId(companyQO.getId(), 0);
            rolePermissionDao.delete(Wrappers.lambdaQuery(AuRolePermissionDO.class).eq(AuRolePermissionDO::getRoleId, superRoleId));
            List<SysFunctionScopePermissionDO> functionScopePermissionDOList = new LambdaQueryChainWrapper<>(functionScopePermissionDao)
                    .eq(SysFunctionScopePermissionDO::getFunctionScopeId, companyQO.getFunctionScopeId())
                    .list();
            if (CollectionUtils.isNotEmpty(functionScopePermissionDOList)) {
                List<Integer> permissionIdList = functionScopePermissionDOList.stream().map(SysFunctionScopePermissionDO::getPermissionId).collect(Collectors.toList());
                rolePermissionDao.insertBatch(superRoleId, permissionIdList);
                // 角色去除取消的功能范围权限
                functionScopeService.subtractRolePermission(auCompanyDO.getFunctionScopeId(), permissionIdList);
            }
            // 更新公司角色的功能范围
            new LambdaUpdateChainWrapper<>(roleDao)
                    .set(AuRoleDO::getFunctionScopeId, companyQO.getFunctionScopeId())
                    .eq(AuRoleDO::getCompanyId, companyQO.getId())
                    .update();
        }

        // 修改超管名称密码
        if (StringUtils.isNotBlank(companyQO.getAdminName())) {
            Integer superAdminId = adminRoleDao.getSuperAdminId(companyQO.getId(), 0);
            Long adminCount = new LambdaQueryChainWrapper<>(adminDao)
                    .eq(AuAdministratorDO::getAdminName, companyQO.getAdminName())
                    .ne(AuAdministratorDO::getId, superAdminId)
                    .count();
            if (adminCount > 0) {
                return ResponseResult.failure(ResultCodeEnum.ADMIN_NAME_REPEAT);
            }
            String password = "";
            if (StringUtils.isNotBlank(companyQO.getPassword())) {
                password = passwordEncoder.encode(companyQO.getPassword());
            }
            new LambdaUpdateChainWrapper<>(adminDao)
                    .set(AuAdministratorDO::getAdminName, companyQO.getAdminName())
                    .set(StringUtils.isNotBlank(companyQO.getPassword()), AuAdministratorDO::getPassword, password)
                    .eq(AuAdministratorDO::getId, superAdminId)
                    .update();
        }
        return ResponseResult.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult deleteCompany(Integer companyId) {
        AuCompanyDO companyDO = companyDao.selectById(companyId);
        // 发送公司删除事件
        mdmEventPublisher.publishCompanyDeleteEvent(companyId);
        // 删除公司所有文件
        minIoManager.removeCompanyBucket(companyDO.getCompanyName());
        companyDao.deleteById(companyId);
        return ResponseResult.success();
    }

    @Override
    public ResponseResult getCompanyIndexConfig(LoginAdminDTO loginAdminDTO) {
        AuCompanyDO companyDO = companyDao.selectById(loginAdminDTO.getCompanyId());
        return ResponseResult.success(companyDO.getIndexConfig());
    }

    @Override
    public ResponseResult setCompanyIndexConfig(String indexConfig, LoginAdminDTO loginAdminDTO) {
        new LambdaUpdateChainWrapper<>(companyDao)
                .set(AuCompanyDO::getIndexConfig, indexConfig)
                .eq(AuCompanyDO::getId, loginAdminDTO.getCompanyId())
                .update();
        return ResponseResult.success();
    }

}