package cn.iocoder.lyzsys.module.tjt.service.employee;

import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.framework.common.util.collection.CollectionUtils;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeePageReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeRespVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeSaveReqVO;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employee.vo.EmployeeSimpleRespVO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.office.OfficeDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearcostbudget.EmployeeYearCostBudgetMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearleaderoutput.EmployeeYearLeaderOutputMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employee.EmployeeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.office.OfficeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.projectroleperson.ProjectRolePersonMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.specialtyrolesplitperson.SpecialtyRoleSplitPersonMapper;
import cn.iocoder.lyzsys.module.tjt.service.office.OfficeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static cn.iocoder.lyzsys.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.EMPLOYEE_IN_USE;
import static cn.iocoder.lyzsys.module.tjt.enums.ErrorCodeConstants.EMPLOYEE_NOT_EXISTS;

@Service
@Validated
public class EmployeeServiceImpl implements EmployeeService {

    @Resource
    private EmployeeMapper employeeMapper;
    @Resource
    private OfficeMapper officeMapper;
    @Resource
    private EmployeeYearCostBudgetMapper employeeYearCostBudgetMapper;
    @Resource
    private EmployeeYearLeaderOutputMapper employeeYearLeaderOutputMapper;
    @Resource
    private ProjectRolePersonMapper projectRolePersonMapper;
    @Resource
    private SpecialtyRoleSplitPersonMapper specialtyRoleSplitPersonMapper;
    @Resource
    private OfficeService officeService;

    @Override
    public Long createEmployee(EmployeeSaveReqVO createReqVO) {
        officeService.validateOfficeExists(createReqVO.getOfficeId());
        EmployeeDO employee = BeanUtils.toBean(createReqVO, EmployeeDO.class);
        if (employee.getEnabledFlag() == null) {
            employee.setEnabledFlag(Boolean.TRUE);
        }
        if (employee.getOfficeLeaderFlag() == null) {
            employee.setOfficeLeaderFlag(Boolean.FALSE);
        }
        employeeMapper.insert(employee);
        return employee.getId();
    }

    @Override
    public void updateEmployee(EmployeeSaveReqVO updateReqVO) {
        validateEmployeeExists(updateReqVO.getId());
        officeService.validateOfficeExists(updateReqVO.getOfficeId());
        EmployeeDO employee = BeanUtils.toBean(updateReqVO, EmployeeDO.class);
        if (employee.getOfficeLeaderFlag() == null) {
            employee.setOfficeLeaderFlag(Boolean.FALSE);
        }
        employeeMapper.updateById(employee);
    }

    @Override
    public void deleteEmployee(Long id) {
        validateEmployeeExists(id);
        if (employeeYearCostBudgetMapper.selectCountByEmployeeId(id) > 0
                || employeeYearLeaderOutputMapper.selectCountByEmployeeId(id) > 0
                || projectRolePersonMapper.selectCountByEmployeeId(id) > 0
                || existsInSpecialtyRoleSplit(id)) {
            throw exception(EMPLOYEE_IN_USE);
        }
        employeeMapper.deleteById(id);
    }

    @Override
    public EmployeeRespVO getEmployee(Long id) {
        EmployeeDO employee = validateEmployeeExists(id);
        Map<Long, OfficeDO> officeMap = getOfficeMap(Collections.singleton(employee.getOfficeId()));
        return toRespVO(employee, officeMap);
    }

    @Override
    public EmployeeDO validateEmployeeExists(Long id) {
        EmployeeDO employee = employeeMapper.selectById(id);
        if (employee == null) {
            throw exception(EMPLOYEE_NOT_EXISTS);
        }
        return employee;
    }

    @Override
    public PageResult<EmployeeRespVO> getEmployeePage(EmployeePageReqVO pageReqVO) {
        PageResult<EmployeeDO> pageResult = employeeMapper.selectPage(pageReqVO);
        Map<Long, OfficeDO> officeMap = getOfficeMap(CollectionUtils.convertSet(pageResult.getList(), EmployeeDO::getOfficeId));
        return BeanUtils.toBean(pageResult, EmployeeRespVO.class, respVO ->
                respVO.setOfficeName(officeMap.containsKey(respVO.getOfficeId())
                        ? officeMap.get(respVO.getOfficeId()).getOfficeName() : null));
    }

    @Override
    public List<EmployeeSimpleRespVO> getEmployeeSimpleList(String keyword, Long officeId, String status,
                                                            Boolean enabledFlag, Boolean officeLeaderFlag) {
        List<EmployeeDO> list = employeeMapper.selectSimpleList(keyword, officeId, status,
                enabledFlag == null ? Boolean.TRUE : enabledFlag, officeLeaderFlag);
        Map<Long, OfficeDO> officeMap = getOfficeMap(CollectionUtils.convertSet(list, EmployeeDO::getOfficeId));
        return BeanUtils.toBean(list, EmployeeSimpleRespVO.class, respVO ->
                respVO.setOfficeName(officeMap.containsKey(respVO.getOfficeId())
                        ? officeMap.get(respVO.getOfficeId()).getOfficeName() : null));
    }

    private boolean existsInSpecialtyRoleSplit(Long employeeId) {
        return specialtyRoleSplitPersonMapper.selectCountByEmployeeId(employeeId) > 0;
    }

    private Map<Long, OfficeDO> getOfficeMap(Set<Long> officeIds) {
        if (officeIds == null || officeIds.isEmpty()) {
            return Collections.emptyMap();
        }
        Set<Long> validOfficeIds = officeIds.stream()
                .filter(Objects::nonNull)
                .collect(java.util.stream.Collectors.toSet());
        if (validOfficeIds.isEmpty()) {
            return Collections.emptyMap();
        }
        return CollectionUtils.convertMap(officeMapper.selectBatchIds(validOfficeIds), OfficeDO::getId);
    }

    private EmployeeRespVO toRespVO(EmployeeDO employee, Map<Long, OfficeDO> officeMap) {
        return BeanUtils.toBean(employee, EmployeeRespVO.class, respVO ->
                respVO.setOfficeName(officeMap.containsKey(respVO.getOfficeId())
                        ? officeMap.get(respVO.getOfficeId()).getOfficeName() : null));
    }

}
