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

import cn.iocoder.lyzsys.framework.common.pojo.PageResult;
import cn.iocoder.lyzsys.framework.common.util.object.BeanUtils;
import cn.iocoder.lyzsys.module.tjt.controller.admin.employeeyearleaderoutput.vo.*;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employee.EmployeeDO;
import cn.iocoder.lyzsys.module.tjt.dal.dataobject.employeeyearleaderoutput.EmployeeYearLeaderOutputDO;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employee.EmployeeMapper;
import cn.iocoder.lyzsys.module.tjt.dal.mysql.employeeyearleaderoutput.EmployeeYearLeaderOutputMapper;
import cn.iocoder.lyzsys.module.tjt.service.employee.EmployeeService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

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

@Service
@Validated
public class EmployeeYearLeaderOutputServiceImpl implements EmployeeYearLeaderOutputService {

    @Resource
    private EmployeeYearLeaderOutputMapper employeeYearLeaderOutputMapper;
    @Resource
    private EmployeeMapper employeeMapper;
    @Resource
    private EmployeeService employeeService;

    @Override
    public Long createEmployeeYearLeaderOutput(EmployeeYearLeaderOutputSaveReqVO createReqVO) {
        EmployeeDO employee = validateEmployeeIsOfficeLeader(createReqVO.getEmployeeId());
        validateDuplicate(null, createReqVO.getEmployeeId(), createReqVO.getOutputYear());
        EmployeeYearLeaderOutputDO output = BeanUtils.toBean(createReqVO, EmployeeYearLeaderOutputDO.class);
        output.setEmployeeName(employee.getEmployeeName());
        output.setLeaderOutputAmount(amount(output.getLeaderOutputAmount()));
        if (output.getEnabledFlag() == null) {
            output.setEnabledFlag(Boolean.TRUE);
        }
        employeeYearLeaderOutputMapper.insert(output);
        return output.getId();
    }

    @Override
    public EmployeeYearLeaderOutputGenerateRespVO generateEmployeeYearLeaderOutput(
            EmployeeYearLeaderOutputGenerateReqVO reqVO) {
        BigDecimal leaderOutputAmount = amount(reqVO.getLeaderOutputAmount());
        List<EmployeeDO> enabledLeaders = employeeMapper.selectEnabledLeaderList();
        Set<Long> existingEmployeeIds = employeeYearLeaderOutputMapper.selectListByOutputYear(reqVO.getOutputYear())
                .stream()
                .map(EmployeeYearLeaderOutputDO::getEmployeeId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        List<EmployeeYearLeaderOutputDO> createList = enabledLeaders.stream()
                .filter(employee -> !existingEmployeeIds.contains(employee.getId()))
                .map(employee -> buildInitialOutput(employee, reqVO.getOutputYear(), leaderOutputAmount))
                .collect(Collectors.toList());
        if (!createList.isEmpty()) {
            employeeYearLeaderOutputMapper.insertBatch(createList);
        }

        EmployeeYearLeaderOutputGenerateRespVO respVO = new EmployeeYearLeaderOutputGenerateRespVO();
        respVO.setOutputYear(reqVO.getOutputYear());
        respVO.setTotalEnabledLeaderCount(enabledLeaders.size());
        respVO.setCreatedCount(createList.size());
        respVO.setSkippedCount(enabledLeaders.size() - createList.size());
        return respVO;
    }

    @Override
    public void updateEmployeeYearLeaderOutput(EmployeeYearLeaderOutputSaveReqVO updateReqVO) {
        validateExists(updateReqVO.getId());
        EmployeeDO employee = validateEmployeeIsOfficeLeader(updateReqVO.getEmployeeId());
        validateDuplicate(updateReqVO.getId(), updateReqVO.getEmployeeId(), updateReqVO.getOutputYear());
        EmployeeYearLeaderOutputDO updateObj = BeanUtils.toBean(updateReqVO, EmployeeYearLeaderOutputDO.class);
        updateObj.setEmployeeName(employee.getEmployeeName());
        updateObj.setLeaderOutputAmount(amount(updateObj.getLeaderOutputAmount()));
        employeeYearLeaderOutputMapper.updateById(updateObj);
    }

    @Override
    public void deleteEmployeeYearLeaderOutput(Long id) {
        validateExists(id);
        employeeYearLeaderOutputMapper.deleteById(id);
    }

    @Override
    public EmployeeYearLeaderOutputRespVO getEmployeeYearLeaderOutput(Long id) {
        return BeanUtils.toBean(validateExists(id), EmployeeYearLeaderOutputRespVO.class);
    }

    @Override
    public PageResult<EmployeeYearLeaderOutputRespVO> getEmployeeYearLeaderOutputPage(
            EmployeeYearLeaderOutputPageReqVO pageReqVO) {
        return BeanUtils.toBean(employeeYearLeaderOutputMapper.selectPage(pageReqVO),
                EmployeeYearLeaderOutputRespVO.class);
    }

    private EmployeeYearLeaderOutputDO validateExists(Long id) {
        EmployeeYearLeaderOutputDO output = employeeYearLeaderOutputMapper.selectById(id);
        if (output == null) {
            throw exception(EMPLOYEE_YEAR_LEADER_OUTPUT_NOT_EXISTS);
        }
        return output;
    }

    private EmployeeDO validateEmployeeIsOfficeLeader(Long employeeId) {
        EmployeeDO employee = employeeService.validateEmployeeExists(employeeId);
        if (!Boolean.TRUE.equals(employee.getEnabledFlag()) || !Boolean.TRUE.equals(employee.getOfficeLeaderFlag())) {
            throw exception(EMPLOYEE_NOT_OFFICE_LEADER);
        }
        return employee;
    }

    private void validateDuplicate(Long id, Long employeeId, Integer outputYear) {
        EmployeeYearLeaderOutputDO duplicate =
                employeeYearLeaderOutputMapper.selectByEmployeeIdAndOutputYear(employeeId, outputYear);
        if (duplicate != null && !Objects.equals(duplicate.getId(), id)) {
            throw exception(EMPLOYEE_YEAR_LEADER_OUTPUT_DUPLICATE);
        }
    }

    private EmployeeYearLeaderOutputDO buildInitialOutput(EmployeeDO employee, Integer outputYear,
                                                          BigDecimal leaderOutputAmount) {
        EmployeeYearLeaderOutputDO output = new EmployeeYearLeaderOutputDO();
        output.setEmployeeId(employee.getId());
        output.setEmployeeName(employee.getEmployeeName());
        output.setOutputYear(outputYear);
        output.setLeaderOutputAmount(leaderOutputAmount);
        output.setSortNo(employee.getSortNo() == null ? 0 : employee.getSortNo());
        output.setEnabledFlag(Boolean.TRUE);
        output.setRemark("");
        return output;
    }

    private BigDecimal amount(BigDecimal value) {
        return value == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
                : value.setScale(2, RoundingMode.HALF_UP);
    }

}
