package cn.iocoder.yudao.module.system.service.workovertime;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.workovertime.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.workovertime.*;
import cn.iocoder.yudao.module.system.dal.mysql.workovertime.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
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;

/**
 * 加班规则 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class WorkOvertimeRuleServiceImpl implements WorkOvertimeRuleService {

    @Resource
    private WorkOvertimeRuleMapper workOvertimeRuleMapper;
    @Resource
    private WorkOvertimeRuleItemMapper workOvertimeRuleItemMapper;
    @Resource
    private WorkOvertimeRuleItemService workOvertimeRuleItemService;
    @Resource
    private WorkOvertimeMoreRuleMapper workOvertimeMoreRuleMapper;
    @Resource
    private WorkOvertimeMoreRuleService workOvertimeMoreRuleService;
    @Resource
    private WorkOvertimeMoreRuleExtMapper workOvertimeMoreRuleExtMapper;
    @Resource
    private WorkOvertimeMoreRuleExtService workOvertimeMoreRuleExtService;
    @Resource
    private WorkOvertimeDeductRuleMapper workOvertimeDeductRuleMapper;
    @Resource
    private WorkOvertimeDeductRuleService workOvertimeDeductRuleService;
    @Resource
    private WorkOvertimeRuleAttendanceGroupService workOvertimeRuleAttendanceGroupService;
    @Resource
    private WorkOvertimeRuleAttendanceGroupMapper workOvertimeRuleAttendanceGroupMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createOrUpdateWorkOvertimeRule(WorkOvertimeRuleSaveReqVO createReqVO) {
        if (createReqVO.getId() == null) {
            this.createWorkOvertimeRule(createReqVO);
            return;
        }
        this.updateWorkOvertimeRule(createReqVO);
    }

    /**
     * 新增
     *
     * @param createReqVO
     */
    private void createWorkOvertimeRule(WorkOvertimeRuleSaveReqVO createReqVO) {
        WorkOvertimeRuleDO workOvertimeRuleDO = BeanUtils.toBean(createReqVO, WorkOvertimeRuleDO.class);
        workOvertimeRuleMapper.insert(workOvertimeRuleDO);
        Long ruleId = workOvertimeRuleDO.getId();
        // --------------------------------------------- 处理考勤组ids ---------------------------------------------
        List<Long> attendanceGroupIds = StrUtil.isEmpty(createReqVO.getAttendanceGroupIds()) ?
                Collections.emptyList() :
                Arrays.stream(createReqVO.getAttendanceGroupIds().split(",")).map(Long::valueOf).collect(Collectors.toList());
        List<WorkOvertimeRuleAttendanceGroupDO> workOvertimeRuleAttendanceGroupDOS = new ArrayList<>();
        attendanceGroupIds.forEach(a -> {
                    workOvertimeRuleAttendanceGroupDOS.add(new WorkOvertimeRuleAttendanceGroupDO().setRuleId(ruleId)
                            .setAttendanceGroupId(a));
                }
        );
        if (CollUtil.isNotEmpty(workOvertimeRuleAttendanceGroupDOS)) {
            workOvertimeRuleAttendanceGroupMapper.insertBatch(workOvertimeRuleAttendanceGroupDOS);
        }
        // --------------------------------------------- 处理考勤组ids ---------------------------------------------

        List<WorkOvertimeRuleItemSaveReqVO> workOvertimeRuleItemSaveReqVOS = createReqVO.getWorkOvertimeRuleItems();
        List<WorkOvertimeRuleItemDO> workOvertimeRuleItemDOS = new ArrayList<>();
        List<WorkOvertimeDeductRuleDO> workOvertimeDeductRuleDOS = new ArrayList<>();
        if (CollUtil.isNotEmpty(workOvertimeRuleItemSaveReqVOS)) {
            for (WorkOvertimeRuleItemSaveReqVO workOvertimeRuleItemSaveReqVO : workOvertimeRuleItemSaveReqVOS) {
                WorkOvertimeRuleItemDO workOvertimeRuleItemDO = BeanUtils.toBean(workOvertimeRuleItemSaveReqVO, WorkOvertimeRuleItemDO.class);
                long ruleItemId = IdWorker.getId();
                workOvertimeRuleItemDO.setId(ruleItemId);
                workOvertimeRuleItemDO.setRuleId(ruleId);
                workOvertimeRuleItemDOS.add(workOvertimeRuleItemDO);
                List<WorkOvertimeDeductRuleSaveReqVO> deductRuleList = workOvertimeRuleItemSaveReqVO.getDeductRules();
                if (CollUtil.isNotEmpty(deductRuleList)) {
                    List<WorkOvertimeDeductRuleDO> workOvertimeDeductRuleDOList = BeanUtils.toBean(deductRuleList, WorkOvertimeDeductRuleDO.class);
                    workOvertimeDeductRuleDOList.forEach(a -> a.setRuleId(ruleId).setRuleItemId(ruleItemId));
                    workOvertimeDeductRuleDOS.addAll(workOvertimeDeductRuleDOList);
                }
            }
            if (CollUtil.isNotEmpty(workOvertimeRuleItemDOS)) {
                workOvertimeRuleItemMapper.insertBatch(workOvertimeRuleItemDOS);
            }
            if (CollUtil.isNotEmpty(workOvertimeDeductRuleDOS)) {
                workOvertimeDeductRuleMapper.insertBatch(workOvertimeDeductRuleDOS);
            }
        }

        WorkOvertimeMoreRuleSaveReqVO moreRule = createReqVO.getMoreRule();
        if (moreRule == null) {
            return;
        }
        WorkOvertimeMoreRuleDO workOvertimeMoreRuleDO = BeanUtils.toBean(moreRule, WorkOvertimeMoreRuleDO.class);
        workOvertimeMoreRuleDO.setRuleId(ruleId);
        workOvertimeMoreRuleMapper.insert(workOvertimeMoreRuleDO);
        Long moreRuleId = workOvertimeMoreRuleDO.getId();

        List<WorkOvertimeMoreRuleExtSaveReqVO> moreRuleExtSaveReqVOS = moreRule.getMoreRuleExtList();
        if (CollUtil.isNotEmpty(moreRuleExtSaveReqVOS)) {
            List<WorkOvertimeMoreRuleExtDO> workOvertimeMoreRuleExtDOS = BeanUtils.toBean(moreRuleExtSaveReqVOS, WorkOvertimeMoreRuleExtDO.class);
            workOvertimeMoreRuleExtDOS.forEach(a -> a.setMoreRuleId(moreRuleId));
            workOvertimeMoreRuleExtMapper.insertBatch(workOvertimeMoreRuleExtDOS);
        }
    }

    /**
     * 修改
     *
     * @param createReqVO
     */
    private void updateWorkOvertimeRule(WorkOvertimeRuleSaveReqVO createReqVO) {
        WorkOvertimeRuleDO workOvertimeRuleDO = BeanUtils.toBean(createReqVO, WorkOvertimeRuleDO.class);
        workOvertimeRuleMapper.updateById(workOvertimeRuleDO);
        Long ruleId = workOvertimeRuleDO.getId();
        // ------------------------------------------- 处理 加班规则考勤组关联 开始 -------------------------------------------
        List<Long> oldAttendanceGroupIds = workOvertimeRuleAttendanceGroupService.getListByRuleId(ruleId)
                .stream().map(WorkOvertimeRuleAttendanceGroupDO::getAttendanceGroupId).collect(Collectors.toList());
        List<Long> attendanceGroupIds = StrUtil.isEmpty(createReqVO.getAttendanceGroupIds()) ?
                Collections.emptyList() :
                Arrays.stream(createReqVO.getAttendanceGroupIds().split(",")).map(Long::valueOf).collect(Collectors.toList());
        List<List<Long>> attendanceGroupIdLists = CollectionUtils.diffList(oldAttendanceGroupIds, attendanceGroupIds, ObjectUtil::equal);
        workOvertimeRuleAttendanceGroupService.insertDeleteBatch(ruleId, attendanceGroupIdLists);
        // ------------------------------------------- 处理 加班规则考勤组关联 结束 -------------------------------------------

        // ------------------------------------------- 处理 加班规则子表 开始 -------------------------------------------
        List<WorkOvertimeRuleItemSaveReqVO> workOvertimeRuleItemSaveReqVOS = createReqVO.getWorkOvertimeRuleItems();
        if (CollUtil.isEmpty(workOvertimeRuleItemSaveReqVOS)) {
            workOvertimeRuleItemSaveReqVOS = Collections.emptyList();
        }
        List<WorkOvertimeRuleItemDO> workOvertimeRuleItemDOS = BeanUtils.toBean(workOvertimeRuleItemSaveReqVOS, WorkOvertimeRuleItemDO.class);
        List<WorkOvertimeRuleItemDO> oldWorkOvertimeRuleItemDOS = workOvertimeRuleItemService.getListByRuleId(ruleId);


        List<List<WorkOvertimeRuleItemDO>> ruleItemLists = CollectionUtils.diffList(oldWorkOvertimeRuleItemDOS, workOvertimeRuleItemDOS,
                (saveVal, newVal) -> ObjectUtil.equal(saveVal.getId(), newVal.getId()));
        // -- 批量新增删除修改
        workOvertimeRuleItemService.insertUpdateDeleteBatch(ruleId, ruleItemLists);

        // ------------------------------------------- 处理 加班规则子表 结束 -------------------------------------------


        // ------------------------------------------- 处理 扣除规则列表 开始 -------------------------------------------
        List<WorkOvertimeDeductRuleDO> oldWorkOvertimeRuleItemDOList = workOvertimeDeductRuleService.getListByRuleId(ruleId);

        List<WorkOvertimeDeductRuleDO> newWorkOvertimeRuleItemDOList = new ArrayList<>();
        for (WorkOvertimeRuleItemSaveReqVO workOvertimeRuleItemSaveReqVO : workOvertimeRuleItemSaveReqVOS) {
            List<WorkOvertimeDeductRuleSaveReqVO> deductRuleList = workOvertimeRuleItemSaveReqVO.getDeductRules();
            if (CollUtil.isEmpty(deductRuleList)) {
                deductRuleList = Collections.emptyList();
            }
            List<WorkOvertimeDeductRuleDO> workOvertimeDeductRuleDOS = BeanUtils.toBean(deductRuleList, WorkOvertimeDeductRuleDO.class);
            workOvertimeDeductRuleDOS.forEach(a -> a.setRuleItemId(workOvertimeRuleItemSaveReqVO.getId()).setRuleId(ruleId));
            newWorkOvertimeRuleItemDOList.addAll(workOvertimeDeductRuleDOS);
        }
        List<List<WorkOvertimeDeductRuleDO>> deductRuleLists = CollectionUtils.diffList(newWorkOvertimeRuleItemDOList, oldWorkOvertimeRuleItemDOList,
                (saveVal, newVal) -> ObjectUtil.equal(saveVal.getId(), newVal.getId()) && ObjectUtil.equal(saveVal.getRuleItemId(), newVal.getRuleItemId()));

        workOvertimeDeductRuleService.insertUpdateDeleteBatch(deductRuleLists);

        // ------------------------------------------- 处理 扣除规则列表 结束 -------------------------------------------


        // ------------------------------------------- 处理 加班规则（更多规则）开始 -------------------------------------------
        WorkOvertimeMoreRuleSaveReqVO moreRules = createReqVO.getMoreRule();
        WorkOvertimeMoreRuleDO workOvertimeMoreRuleDO = BeanUtils.toBean(moreRules, WorkOvertimeMoreRuleDO.class);
        workOvertimeMoreRuleMapper.updateById(workOvertimeMoreRuleDO);
        // ------------------------------------------- 处理 加班规则（更多规则）结束 -------------------------------------------

        // ------------------------------------------- 处理 加班更多规则拓展 开始 -------------------------------------------
        List<WorkOvertimeMoreRuleExtSaveReqVO> moreRuleExtSaveReqVOS = moreRules.getMoreRuleExtList();
        if (CollUtil.isEmpty(moreRuleExtSaveReqVOS)) {
            moreRuleExtSaveReqVOS = Collections.emptyList();
        }
        List<WorkOvertimeMoreRuleExtDO> workOvertimeMoreRuleExtDOS = BeanUtils.toBean(moreRuleExtSaveReqVOS, WorkOvertimeMoreRuleExtDO.class);
        //查询旧的
        List<WorkOvertimeMoreRuleExtDO> oldWorkOvertimeMoreRuleExtDOS = workOvertimeMoreRuleExtService.getListByMoreRuleId(workOvertimeMoreRuleDO.getId());
        List<List<WorkOvertimeMoreRuleExtDO>> moreRuleLists = CollectionUtils.diffList(oldWorkOvertimeMoreRuleExtDOS, workOvertimeMoreRuleExtDOS,
                (saveVal, newVal) -> ObjectUtil.equal(saveVal.getId(), newVal.getId()));

        workOvertimeMoreRuleExtService.insertUpdateDeleteBatch(workOvertimeMoreRuleDO.getId(), moreRuleLists);
        // ------------------------------------------- 处理 加班更多规则拓展 结束 -------------------------------------------
    }

    @Override
    public void deleteWorkOvertimeRule(Long id) {
        // 删除
        workOvertimeRuleMapper.deleteById(id);
        // 同步删除考勤组加班规则关联数据
        workOvertimeRuleAttendanceGroupMapper.delete(new LambdaQueryWrapper<WorkOvertimeRuleAttendanceGroupDO>()
                .eq(WorkOvertimeRuleAttendanceGroupDO::getRuleId, id));
    }

    @Override
    public WorkOvertimeRuleDO getWorkOvertimeRule(Long id) {
        WorkOvertimeRuleDO workOvertimeRuleDO = workOvertimeRuleMapper.selectById(id);
        List<Long> workOvertimeRuleAttendanceGroupDOS = workOvertimeRuleAttendanceGroupService.getListByRuleId(id)
                .stream().map(WorkOvertimeRuleAttendanceGroupDO::getAttendanceGroupId).collect(Collectors.toList());

        String attendanceGroupIds = StrUtil.join(",", workOvertimeRuleAttendanceGroupDOS);
        workOvertimeRuleDO.setAttendanceGroupIds(attendanceGroupIds);
        List<WorkOvertimeDeductRuleDO> deductRules = workOvertimeDeductRuleService.getListByRuleId(id);
        Map<Long, List<WorkOvertimeDeductRuleDO>> deductRuleMap = deductRules.stream().collect(Collectors.groupingBy(WorkOvertimeDeductRuleDO::getRuleItemId));
        List<WorkOvertimeRuleItemDO> workOvertimeRuleItems = workOvertimeRuleItemService.getListByRuleId(id);
        workOvertimeRuleItems.forEach(a -> a.setDeductRules(deductRuleMap.get(a.getId())));
        WorkOvertimeMoreRuleDO moreRule = workOvertimeMoreRuleService.getByRuleId(id);
        List<WorkOvertimeMoreRuleExtDO> moreRuleExtList = workOvertimeMoreRuleExtService.getListByMoreRuleId(moreRule.getId());
        moreRule.setMoreRuleExtList(moreRuleExtList);
        return workOvertimeRuleDO.setMoreRule(moreRule).setWorkOvertimeRuleItems(workOvertimeRuleItems);
    }

    public static void main(String[] args) {
        List<List<Long>> attendanceGroupIdLists = CollectionUtils.diffList(Arrays.asList(1L, 2L), Arrays.asList(2L, 3L), ObjectUtil::equal);
        System.out.println(attendanceGroupIdLists);
    }

    @Override
    public PageResult<WorkOvertimeRuleDO> getWorkOvertimeRulePage(WorkOvertimeRulePageReqVO pageReqVO) {
        IPage<WorkOvertimeRuleDO> vos = workOvertimeRuleMapper.getWorkOvertimeRulePage(pageReqVO, MyBatisUtils.buildPage(pageReqVO));
        vos.getRecords().forEach(a -> a.setWorkOvertimeRuleItems(workOvertimeRuleItemService.getListByRuleId(a.getId())));
        return new PageResult<>(vos.getRecords(), vos.getTotal());
    }


}
