package cn.iocoder.yudao.module.company.service.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.company.entity.Company;
import cn.iocoder.yudao.module.company.vo.CompanyRespVO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.permission.dto.RoleReqDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.api.user.dto.UserDTO;
import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum;
import cn.iocoder.yudao.module.system.enums.permission.RoleTypeEnum;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.iocoder.yudao.module.company.vo.CompanyReqVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.iocoder.yudao.module.company.mapper.CompanyMapper;
import cn.iocoder.yudao.module.company.service.CompanyService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_NOT_EXISTS;
import static java.util.Collections.singleton;

/**
 * 企业信息表（每个租户的下属企业信息）;(dl_company)表服务实现类
 * @author : http://www.chiner.pro
 * @date : 2024-7-31
 */
@Service
public class CompanyServiceImpl extends ServiceImpl<CompanyMapper, Company> implements CompanyService {
    @Autowired
    private CompanyMapper companyMapper;
    @Resource
    @Lazy // 延迟，避免循环依赖报错
    private AdminUserApi adminUserApi;
    @Resource
    private RoleApi roleApi;
    @Resource
    private PermissionApi permissionApi;
    @Resource
    private DeptApi deptApi;


     /**
      * 获得企业信息表（每个租户的下属企业信息）分页
      * @param pageReqVO 分页查询条件
      * @param page  分页对象
      * @author vinjor-M
      */
     @Override
     public IPage<Company> queryListPage(CompanyReqVO pageReqVO, Page<Company> page) {
         return companyMapper.selectListPage(pageReqVO,page);
     }

    /**
     * 新增企业信息
     *
     * @param companyRespVO 企业对象
     * @author vinjor-M
     * @date 9:56 2024/8/2
     **/
    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public void saveDataObj(CompanyRespVO companyRespVO) {
        try {
            /*1.保存企业信息*/
            this.save(companyRespVO);
            /*2.新增企业部门信息*/
            DeptRespDTO deptRespDTO = new DeptRespDTO();
            deptRespDTO.setName(companyRespVO.getCorpName());
            deptRespDTO.setStatus(CommonStatusEnum.ENABLE.getStatus());
            //上级部门为本租户顶级部门
            DeptRespDTO parentDept = deptApi.getDeptByParentId(0L);
            deptRespDTO.setParentId(parentDept.getId());
            Long deptId = deptApi.saveDept(deptRespDTO);
            /*3.新增企业管理员用户信息并配置角色*/
            UserDTO userDTO = new UserDTO();
            userDTO.setUsername(companyRespVO.getLoginAccount());
            userDTO.setNickname(companyRespVO.getContactName());
            userDTO.setDeptId(deptId);
            userDTO.setPassword(companyRespVO.getPassword());
            userDTO.setMobile(companyRespVO.getMobilePhone());
            Long userId = adminUserApi.createUser(userDTO);
            Set<String> roleCodes = new HashSet<>(Arrays.asList(companyRespVO.getServiceCodes().split(StrUtil.COMMA)));
            permissionApi.assignUserRole(userId, roleCodes);
        } catch (ServiceException e) {
            throw exception(new ErrorCode(e.getCode(), e.getMessage()));
        }
    }

    /**
     * 更新企业信息
     *
     * @param companyRespVO 企业对象
     * @author vinjor-M
     * @date 9:56 2024/8/2
     **/
    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public void updateDataObj(CompanyRespVO companyRespVO) {
        try {
            //查出原有数据
            Company oldCompany = this.getById(companyRespVO.getId());
            if(!companyRespVO.getServiceCodes().equals(oldCompany.getServiceCodes())){
                //服务发生变化，变更企业管理员的角色权限
                Set<String> roleCodes = new HashSet<>(Arrays.asList(companyRespVO.getServiceCodes().split(StrUtil.COMMA)));
                //根据企业管理员登录账户查出userId
                AdminUserRespDTO adminUserRespDTO = adminUserApi.getUserByUsername(oldCompany.getLoginAccount());
                permissionApi.assignUserRole(adminUserRespDTO.getId(),roleCodes);
            }
            //正常更新数据
            this.updateById(companyRespVO);
        }catch (ServiceException e) {
            throw exception(new ErrorCode(e.getCode(), e.getMessage()));
        }
    }

    /**
     * 删除企业
     *
     * @param id 企业id
     * @author vinjor-M
     * @date 16:33 2024/8/3
     **/
    @Override
    @DSTransactional // 多数据源，使用 @DSTransactional 保证本地事务，以及数据源的切换
    public void removeDataObj(String id) {
        try {
            Company company = this.getById(id);
            /*1.查出本租户下与本企业名称相同的二级部门，并取出下级所有部门 */
            DeptRespDTO parentDept = deptApi.getDeptByParentId(0L);
            DeptRespDTO thisDept = deptApi.getDeptByParentIdAndName(parentDept.getId(),company.getCorpName());
            List<DeptRespDTO> allChildDeptList = deptApi.getChildDeptList(thisDept.getId());
            allChildDeptList.add(thisDept);
            /*2.删除所有部门的用户和部门---这里挨个删除，为了记录日志和级联删除对应的权限 */
            Set<Long> deptIds = convertSet(allChildDeptList, DeptRespDTO::getId);
            List<AdminUserRespDTO> userRespDTOList = adminUserApi.getUserListByDeptIds(deptIds);
            userRespDTOList.forEach(user->adminUserApi.deleteUser(user.getId()));
            deptApi.deleteDept(deptIds);
            /*3.删除本企业 */
            this.removeById(id);
        }catch (ServiceException e) {
            throw exception(new ErrorCode(e.getCode(), e.getMessage()));
        }
    }

}