package cn.iocoder.yudao.module.smartfactory.service.staff;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.common.util.string.DTO.IdCardDO;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.datapermission.core.util.DataPermissionUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.smartfactory.controller.admin.screendata.factory.vo.StaffDataRespVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.staff.vo.*;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.staff.StaffDO;
import cn.iocoder.yudao.module.smartfactory.dal.mysql.staff.StaffMapper;
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.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.STAFF_NOT_EXISTS;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_IMPORT_LIST_IS_EMPTY;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.USER_USERNAME_EXISTS;


/**
 * 员工 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class StaffServiceImpl implements StaffService {

    @Resource
    private StaffMapper staffMapper;

    @Resource
    private DictDataApi dictDataApi;
    @Resource
    private DeptApi deptApi;
    @Resource
    private AdminUserApi adminUserApi;

    @Override
    public Long createStaff(StaffSaveReqVO createReqVO) {

        // 身份证号是否已经存在
        validateUserForCreate(null, null, null, createReqVO.getIdCard());

        // 插入
        StaffDO staff = BeanUtils.toBean(createReqVO, StaffDO.class);
        staffMapper.insert(staff);
        // 返回
        return staff.getId();
    }

    @Override
    public void updateStaff(StaffSaveReqVO updateReqVO) {
        StaffDO staff = staffMapper.selectById(updateReqVO.getId());
        if (staff == null) {
            throw exception(STAFF_NOT_EXISTS);
        }

        if (!staff.getIdCard().equals(updateReqVO.getIdCard()) || !staff.getNickName().equals(updateReqVO.getNickName())) {
            // 校验用户名、身份证号是否已经存在
            Long cunt = staffMapper.selectCount(new LambdaQueryWrapperX<StaffDO>()
                    .neIfPresent(StaffDO::getId, updateReqVO.getId())
                    .eqIfPresent(StaffDO::getIdCard, updateReqVO.getIdCard())
                    .eqIfPresent(StaffDO::getNickName, updateReqVO.getNickName()));
            if (cunt > 0) {
                throw exception(USER_USERNAME_EXISTS);
            }
        }

        // 更新
        StaffDO updateObj = BeanUtils.toBean(updateReqVO, StaffDO.class);
        staffMapper.updateById(updateObj);
    }

    @Override
    public void deleteStaff(Long id) {
        // 删除
        staffMapper.deleteById(id);
    }

    private void validateUserForCreate(Long id, String username, String mobile, String idCard) {
        // 关闭数据权限，避免因为没有数据权限，查询不到数据，进而导致唯一校验不正确
        DataPermissionUtils.executeIgnore(() -> {

            // 校验用户名、身份证号是否已经存在
            Long cunt = staffMapper.selectCount(new LambdaQueryWrapperX<StaffDO>()
                    .eqIfPresent(StaffDO::getId, id)
                    .eqIfPresent(StaffDO::getNickName, username)
                    .eqIfPresent(StaffDO::getIdCard, idCard)
                    .eqIfPresent(StaffDO::getMobile, mobile));
            if (cunt > 0) {
                throw exception(USER_USERNAME_EXISTS);
            }
        });
    }

    @Override
    public StaffDO getStaff(Long id) {
        return staffMapper.selectById(id);
    }

    @Override
    public PageResult<StaffDO> getStaffPage(StaffPageReqVO pageReqVO) {
        return staffMapper.selectPage(pageReqVO);
    }

    @Override
    public StaffDataRespVO getStaffData(Long factoryId) {
        StaffDataRespVO vo = new StaffDataRespVO();
        List<StaffDO> dos = staffMapper.selectList(new LambdaQueryWrapperX<StaffDO>()
                .ne(StaffDO::getStatus, 0));

        // 获取工种信息
        List<DictDataRespDTO> workTypeVOs = dictDataApi.getDictDataList("user_work_type").getCheckedData();
        Map<String, String> workTypeMap = workTypeVOs.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));

        // 设置工种名称
        dos.forEach(item -> {
            if (item.getWorkTypeId() != null) {
                item.setPostName(workTypeMap.getOrDefault(item.getWorkTypeId().toString(), ""));
            }
        });

        vo.setTotal(dos.size());
        vo.setMaleTotal((int) dos.stream().filter(a -> a.getSex() != null && a.getSex() == 0).count());
        vo.setFemaleTotal((int) dos.stream().filter(a -> a.getSex() != null && a.getSex() == 1).count());
        vo.setStaffInfos(dos);
        return vo;
    }

    @Override
    public Integer getCount() {
        return Math.toIntExact(staffMapper.selectCount(new LambdaQueryWrapperX<StaffDO>().eq(StaffDO::getStatus, 1)));
    }

    @Override
    public StaffDataRespVO getStaffDataV2(Long factoryId) {
        StaffDataRespVO vo = new StaffDataRespVO();
        List<StaffDO> dos = staffMapper.getStaffDataV2(factoryId);
        // 获取工种信息
        List<DictDataRespDTO> workTypeVOs = dictDataApi.getDictDataList("user_work_type").getCheckedData();
        Map<String, String> workTypeMap = workTypeVOs.stream().collect(Collectors.toMap(DictDataRespDTO::getValue, DictDataRespDTO::getLabel));

        // 设置工种名称
        dos.forEach(item -> {
            item.setPostName(workTypeMap.getOrDefault(item.getWorkTypeId().toString(), ""));
        });
        vo.setTotal(dos.size());
        vo.setMaleTotal((int) dos.stream().filter(a -> a.getSex() == 0).count());
        vo.setFemaleTotal((int) dos.stream().filter(a -> a.getSex() == 1).count());
        vo.setStaffInfos(dos);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class) // 添加事务，异常则回滚所有导入
    public StaffImportRespVO importUserList(List<StaffImportExcelVO> importUsers, Boolean updateSupport) {
        if (CollUtil.isEmpty(importUsers)) {
            throw exception(USER_IMPORT_LIST_IS_EMPTY);
        }
        StaffImportRespVO respVO = StaffImportRespVO.builder()
                .createUsernames(new ArrayList<>())
                .updateUsernames(new ArrayList<>())
                .failureUsernames(new HashMap<>()).build();

        importUsers.forEach(importUser -> {
            if (importUser.getNickName() == null) {
                return;
            }
            //校验，判断是否有不符合的原因
            try {
                if (!updateSupport) {
                    validateUserForCreate(null, importUser.getNickName(), null, importUser.getIdCard());
                }
            } catch (ServiceException ex) {
                respVO.getFailureUsernames().put(importUser.getNickName(), ex.getMessage());
                return;
            }

            StaffDO updateUser = BeanUtils.toBean(importUser, StaffDO.class);

            //解析身份证号码
            IdCardDO idCardDO = StrUtils.IdCardAnalysis(updateUser.getIdCard());

            //设置 性别、年龄
            updateUser.setSex(idCardDO.getSex());
            updateUser.setAge(idCardDO.getAge());
            // 设置银行卡名称、 银行卡号
            updateUser.setBankName(importUser.getBankName());
            updateUser.setBankNo(importUser.getBankNo());

            //设置部门ID
            if (StrUtil.isNotEmpty(importUser.getFactoryName())) {

                //excel接受到工厂名称格式为 id:name
                updateUser.setFactoryId(Long.valueOf(importUser.getFactoryName().split(":")[0]));
            }

            //设置岗位ID
            if (StrUtil.isNotEmpty(importUser.getWorkTypeName())) {

                //excel接受到工种名称格式为 id:name
                updateUser.setWorkTypeId(Integer.valueOf(importUser.getWorkTypeName().split(":")[0]));
            }

            // 设置业务类型
            if (StrUtil.isNotEmpty(importUser.getBusinessTypeName())) {

                updateUser.setBusinessType(Integer.valueOf(importUser.getBusinessTypeName().split(":")[0]));
            }

            // 判断如果不存在，在进行插入
            if (updateSupport) {
                StaffDO staffDO = staffMapper.selectOne(new LambdaQueryWrapperX<StaffDO>()
                        .eqIfPresent(StaffDO::getIdCard, importUser.getIdCard())
                        .likeIfPresent(StaffDO::getNickName, importUser.getNickName()));

                if (staffDO != null) {
                    updateUser.setId(staffDO.getId());
                    staffMapper.updateById(updateUser);
                    respVO.getUpdateUsernames().add(importUser.getNickName());
                    return;
                }
            }

            // 插入用户
            staffMapper.insert(updateUser);
            respVO.getCreateUsernames().add(importUser.getNickName());
        });

        return respVO;
    }

    @Override
    public List<StaffDO> getListByFactory(Long factoryId, Boolean isIn) {
        return staffMapper.selectList(new LambdaQueryWrapperX<StaffDO>()
                .eq(isIn, StaffDO::getFactoryId, factoryId)
                .ne(!isIn, StaffDO::getFactoryId, factoryId)
                .ne(StaffDO::getStatus, 0));
    }

    @Override
    public List<StaffDO> getListByFactoryIds(Collection<Long> factoryIds) {

        return staffMapper.selectList(StaffDO::getFactoryId, factoryIds);
    }

    @Override
    public List<StaffDO> getList(Collection<Long> staffIds) {
        return staffMapper.selectList(StaffDO::getId, staffIds);
    }

    @Override
    public List<StaffDO> getListByFactoryId(Long factoryId, String nickName, Long workTypeId) {
        return staffMapper.selectList(new LambdaQueryWrapperX<StaffDO>()
                .eq(factoryId != null, StaffDO::getFactoryId, factoryId)
                .eq(workTypeId != null, StaffDO::getWorkTypeId, workTypeId)
                .like(StrUtil.isNotEmpty(nickName), StaffDO::getNickName, nickName));
    }

    @Override
    public Long getTheFactoryOfTheCurrentlyLoggedInUser() {
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        //获取当前登录用户
        AdminUserRespDTO adminUserRespDTO = adminUserApi.getUser(userId).getCheckedData();
        Long deptId = null;
        if (adminUserRespDTO != null) {
            deptId = adminUserRespDTO.getDeptId();
        }
        DeptRespDTO dto = null;
        if (deptId != null) {
            dto = deptApi.getDept(deptId).getCheckedData();
        }
        // 获取当前登录用户所属部门
        if (dto == null) {
            return null;
        }
        return dto.getFactoryId();
    }

    @Override
    public StaffDO getStaffByUserId(Long userId) {

        return staffMapper.selectStaffByUserId(userId);
    }

    @Override
    public void updateStaffSalary(StaffSalaryUpdateVO updateReqVO) {

        if (staffMapper.selectById(updateReqVO.getId()) == null) {
            throw exception(STAFF_NOT_EXISTS);
        }

        // 更新
        StaffDO updateObj = BeanUtils.toBean(updateReqVO, StaffDO.class);
        staffMapper.updateById(updateObj);
    }
}
