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

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.smartfactory.controller.admin.handlinggroup.vo.HandlingGroupListVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.handlinggroupamountspecifications.dto.HandlingGroupAmountSpecificationsPageReqDTO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.handlinggroupamountspecifications.dto.HandlingGroupAmountSpecificationsTotalNumDTO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.handlinggroupamountspecifications.vo.*;
import cn.iocoder.yudao.module.smartfactory.controller.admin.handlinggroupuseramount.vo.HandlingGroupUserAmountItemVO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.handlinggroupamountspecifications.HandlingGroupAmountSpecificationsDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.handlinggroupuseramount.HandlingGroupUserAmountDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.handlingspecifications.HandlingSpecificationsDO;
import cn.iocoder.yudao.module.smartfactory.dal.mysql.handlinggroup.HandlingGroupMapper;
import cn.iocoder.yudao.module.smartfactory.dal.mysql.handlinggroupamountspecifications.HandlingGroupAmountSpecificationsMapper;
import cn.iocoder.yudao.module.smartfactory.service.handlinggroupuseramount.HandlingGroupUserAmountService;
import cn.iocoder.yudao.module.smartfactory.service.handlingspecifications.HandlingSpecificationsService;
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.user.AdminUserApi;
import com.alibaba.druid.sql.visitor.functions.Lpad;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.ADDED_A_HANDLING_GROUP_WITH_DUPLICATE_DATA;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.NEW_DATA_AND_OLD_DATA_HAVE_DUPLICATE_HANDLING_GROUP;

/**
 * 搬运组工资规格关联 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class HandlingGroupAmountSpecificationsServiceImpl extends ServiceImpl<HandlingGroupAmountSpecificationsMapper, HandlingGroupAmountSpecificationsDO> implements HandlingGroupAmountSpecificationsService {

    @Resource
    private HandlingGroupAmountSpecificationsMapper handlingGroupAmountSpecificationsMapper;
    @Resource
    private HandlingGroupMapper handlingGroupMapper;
    @Resource
    private HandlingSpecificationsService handlingSpecificationsService;
    @Resource
    private HandlingGroupUserAmountService handlingGroupUserAmountService;

    @Resource
    private AdminUserApi userApi;

    @Resource
    private DeptApi deptApi;

    private static final BigDecimal THOUSANDTH = new BigDecimal("0.001");


    @Override
    public HandlingGroupAmountSpecificationsDO getHandlingGroupAmountSpecifications(Long id) {
        return handlingGroupAmountSpecificationsMapper.getHandlingGroupAmountSpecifications(id);
    }

    @Override
    public List<HandlingGroupAmountSpecificationsDO> getHandlingGroupAmountSpecificationsList(Long factoryId, String dateStr, Long handlingGroupId) {
        return handlingGroupAmountSpecificationsMapper.getHandlingGroupAmountSpecificationsList(factoryId, dateStr, handlingGroupId);
    }

    @Override
    public PageResult<HandlingGroupAmountSpecificationsDO> getHandlingGroupAmountSpecificationsPage(HandlingGroupAmountSpecificationsPageReqVO pageReqVO) {
        // 判断当前登录人是否属于工厂主管
        List<DeptRespDTO> deptRespDTOS = deptApi.getDeptByLeaderId(getLoginUserId()).getCheckedData();
        List<DeptRespDTO> factoryDeptVOs = deptRespDTOS.stream().filter(item -> item.getFactoryId() != null).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(factoryDeptVOs)) {
            pageReqVO.setFactoryIds(factoryDeptVOs.stream().map(DeptRespDTO::getFactoryId).distinct().collect(Collectors.toList()));
        }
        IPage<HandlingGroupAmountSpecificationsDO> pageResult = handlingGroupAmountSpecificationsMapper.getHandlingGroupAmountSpecificationsPage(MyBatisUtils.buildPage(pageReqVO), pageReqVO);
        return new PageResult<>(pageResult.getRecords(), pageResult.getTotal());
    }


    @Override
    public void batchCreate(HandlingGroupAmountSpecificationsBatchCreateVO vo) {
        List<Long> newHandlingGroupIds = vo.getHandlingGroupList().stream().map(HandlingGroupListVO::getHandlingGroupId).collect(Collectors.toList());
        // -- 先判断 新增之中有没有冲突的搬运组
        int num = newHandlingGroupIds.size();
        List<Long> distinctList = newHandlingGroupIds.stream().distinct().collect(Collectors.toList());
        if (num > distinctList.size()) {
            throw exception(ADDED_A_HANDLING_GROUP_WITH_DUPLICATE_DATA);
        }
        // -- 再判断是否有重复的数据 - 同一天 同一个工厂 不可以出现两个相同的搬运组
        List<HandlingGroupAmountSpecificationsDO> oldList = this.list(new LambdaQueryWrapper<HandlingGroupAmountSpecificationsDO>()
                .eq(HandlingGroupAmountSpecificationsDO::getFactoryId, vo.getFactoryId())
                .eq(HandlingGroupAmountSpecificationsDO::getDateStr, vo.getDateStr()));
        List<Long> oldHandlingGroupIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(oldList)) {
            oldHandlingGroupIds = oldList.stream().map(HandlingGroupAmountSpecificationsDO::getHandlingGroupId).collect(Collectors.toList());
        }
        if (CollUtil.isNotEmpty(CollUtil.intersection(distinctList, oldHandlingGroupIds))) {
            throw exception(NEW_DATA_AND_OLD_DATA_HAVE_DUPLICATE_HANDLING_GROUP);
        }


        List<HandlingGroupAmountSpecificationsDO> list = new ArrayList<>();
        // -- 获取到所有的规格列表
        List<Long> handlingSpecificationsIds = vo.getHandlingGroupList().stream()
                .flatMap(group -> group.getItemList().stream())
                .map(HandlingGroupAmountSpecificationsBatchCreateItemVO::getHandlingSpecificationsId)
                .collect(Collectors.toList());
        List<HandlingSpecificationsDO> handlingSpecificationsDOS = handlingSpecificationsService.list(new LambdaQueryWrapper<HandlingSpecificationsDO>()
                .in(HandlingSpecificationsDO::getId, handlingSpecificationsIds));
        Map<Long, HandlingSpecificationsDO> map = handlingSpecificationsDOS.stream().collect(Collectors.toMap(HandlingSpecificationsDO::getId, item -> item));

        for (HandlingGroupListVO handlingGroupListVO : vo.getHandlingGroupList()) {
            for (HandlingGroupAmountSpecificationsBatchCreateItemVO itemVO : handlingGroupListVO.getItemList()) {
                HandlingGroupAmountSpecificationsDO handlingGroupAmountSpecificationsDO = new HandlingGroupAmountSpecificationsDO();
                BigDecimal totalAmount;
                HandlingSpecificationsDO handlingSpecificationsDO = map.get(itemVO.getHandlingSpecificationsId());
                if (handlingSpecificationsDO == null) {
                    continue;
                }
                if (handlingSpecificationsDO.getType() == 0) {
                    totalAmount = new BigDecimal(itemVO.getTotalCount().toString()).multiply(handlingSpecificationsDO.getUnitPrice());
                } else {
                    totalAmount = new BigDecimal(itemVO.getTotalCount().toString()).multiply(handlingSpecificationsDO.getWeight())
                            .multiply(handlingSpecificationsDO.getUnitPrice().multiply(THOUSANDTH));
                }
                handlingGroupAmountSpecificationsDO.setFactoryId(vo.getFactoryId());
                handlingGroupAmountSpecificationsDO.setDateStr(vo.getDateStr());
                handlingGroupAmountSpecificationsDO.setHandlingSpecificationsId(itemVO.getHandlingSpecificationsId());
                handlingGroupAmountSpecificationsDO.setAmount(totalAmount);
                handlingGroupAmountSpecificationsDO.setTotalCount(itemVO.getTotalCount());
                handlingGroupAmountSpecificationsDO.setHandlingGroupId(handlingGroupListVO.getHandlingGroupId());
                handlingGroupAmountSpecificationsDO.setStaffId(handlingGroupListVO.getStaffId());
                list.add(handlingGroupAmountSpecificationsDO);
            }
        }
        handlingGroupAmountSpecificationsMapper.insertBatch(list);
    }

    @Override
    public void batchUpdate(HandlingGroupAmountSpecificationsBatchUpdateVO vo) {
        // 先通过 工厂 + 日期 + 组id 获取到当前编辑的搬运组
        List<HandlingGroupAmountSpecificationsDO> list = handlingGroupAmountSpecificationsMapper.selectList(new LambdaQueryWrapper<HandlingGroupAmountSpecificationsDO>()
                .eq(HandlingGroupAmountSpecificationsDO::getFactoryId, vo.getFactoryId())
                .eq(HandlingGroupAmountSpecificationsDO::getHandlingGroupId, vo.getHandlingGroupId())
                .eq(HandlingGroupAmountSpecificationsDO::getDateStr, vo.getDateStr()));

        List<Long> handlingSpecificationsIds = vo.getItemList().stream().map(HandlingGroupAmountSpecificationsBatchCreateItemVO::getHandlingSpecificationsId).distinct().collect(Collectors.toList());
        List<HandlingSpecificationsDO> handlingSpecificationsDOS = handlingSpecificationsService.list(new LambdaQueryWrapper<HandlingSpecificationsDO>()
                .in(HandlingSpecificationsDO::getId, handlingSpecificationsIds));
        Map<Long, HandlingSpecificationsDO> map = handlingSpecificationsDOS.stream().collect(Collectors.toMap(HandlingSpecificationsDO::getId, item -> item));
        Map<Long, HandlingGroupAmountSpecificationsBatchCreateItemVO> handlingGroupAmountSpecificationsMap = vo.getItemList().stream()
                .collect(Collectors.toMap(HandlingGroupAmountSpecificationsBatchCreateItemVO::getId, item -> item));

        for (HandlingGroupAmountSpecificationsDO item : list) {
            BigDecimal totalAmount;
            HandlingGroupAmountSpecificationsBatchCreateItemVO handlingGroupAmountSpecificationsBatchCreateItemVO
                    = handlingGroupAmountSpecificationsMap.get(item.getId());
            item.setHandlingSpecificationsId(handlingGroupAmountSpecificationsBatchCreateItemVO.getHandlingSpecificationsId());
            HandlingSpecificationsDO handlingSpecificationsDO = map.get(item.getHandlingSpecificationsId());
            if (handlingSpecificationsDO == null) {
                continue;
            }
            if (handlingSpecificationsDO.getType() == 0) {
                totalAmount = new BigDecimal(handlingGroupAmountSpecificationsBatchCreateItemVO.getTotalCount().toString()).multiply(handlingSpecificationsDO.getUnitPrice());
            } else {
                totalAmount = new BigDecimal(handlingGroupAmountSpecificationsBatchCreateItemVO.getTotalCount().toString()).multiply(handlingSpecificationsDO.getWeight())
                        .multiply(handlingSpecificationsDO.getUnitPrice().multiply(THOUSANDTH));
            }
            item.setAmount(totalAmount);
            item.setTotalCount(handlingGroupAmountSpecificationsBatchCreateItemVO.getTotalCount());
            item.setStaffId(vo.getStaffId());
        }
        handlingGroupAmountSpecificationsMapper.updateBatch(list);
    }

    @Override
    public void batchDelete(HandlingGroupAmountSpecificationsBatchDelVO vo) {
        List<HandlingGroupAmountSpecificationsDO> list = handlingGroupAmountSpecificationsMapper.selectList(new LambdaQueryWrapper<HandlingGroupAmountSpecificationsDO>()
                .eq(HandlingGroupAmountSpecificationsDO::getFactoryId, vo.getFactoryId())
                .eq(HandlingGroupAmountSpecificationsDO::getHandlingGroupId, vo.getHandlingGroupId())
                .eq(HandlingGroupAmountSpecificationsDO::getDateStr, vo.getDateStr()));
        List<Long> ids = list.stream().map(HandlingGroupAmountSpecificationsDO::getId).collect(Collectors.toList());
        handlingGroupAmountSpecificationsMapper.deleteBatchIds(ids);

        handlingGroupUserAmountService.remove(new LambdaQueryWrapper<HandlingGroupUserAmountDO>()
                .eq(HandlingGroupUserAmountDO::getFactoryId, vo.getFactoryId())
                .eq(HandlingGroupUserAmountDO::getHandlingGroupId, vo.getHandlingGroupId())
                .eq(HandlingGroupUserAmountDO::getDateStr, vo.getDateStr()));
    }

    @Override
    public HandlingGroupAmountSpecificationsTotalNumVO getTotalNum(HandlingGroupAmountSpecificationsTotalNumDTO dto) {
        // 判断当前登录人是否属于工厂主管
        List<DeptRespDTO> deptRespDTOS = deptApi.getDeptByLeaderId(getLoginUserId()).getCheckedData();
        List<DeptRespDTO> factoryDeptVOs = deptRespDTOS.stream().filter(item -> item.getFactoryId() != null).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(factoryDeptVOs)) {
            dto.setFactoryIds(factoryDeptVOs.stream().map(DeptRespDTO::getFactoryId).distinct().collect(Collectors.toList()));
        }
        return handlingGroupAmountSpecificationsMapper.getTotalNum(dto);
    }

    @Override
    public BigDecimal getAmountSubtotal(Integer totalCount, Long handlingSpecificationsId) {
        HandlingSpecificationsDO handlingSpecificationsDO = handlingSpecificationsService.getById(handlingSpecificationsId);
        BigDecimal totalAmount;
        if (handlingSpecificationsDO.getType() == 0) {
            totalAmount = new BigDecimal(totalCount.toString()).multiply(handlingSpecificationsDO.getUnitPrice());
        } else {
            totalAmount = new BigDecimal(totalCount.toString()).multiply(handlingSpecificationsDO.getWeight())
                    .multiply(handlingSpecificationsDO.getUnitPrice().multiply(THOUSANDTH));
        }
        return totalAmount;
    }

    @Override
    public PageResult<HandlingGroupAmountSpecificationsRespVO> getHandlingGroupAmountSpecificationsPageV2(HandlingGroupAmountSpecificationsPageReqDTO pageReqVO) {
        IPage<HandlingGroupAmountSpecificationsVO> handlingGroupPage = handlingGroupMapper.selectPageListByDateStr(MyBatisUtils.buildPage(pageReqVO), pageReqVO);
        // 搬运规格ids - 拼接 一起查询
        PageResult<HandlingGroupAmountSpecificationsVO> resultPage = new PageResult<>(handlingGroupPage.getRecords(), handlingGroupPage.getTotal());
        PageResult<HandlingGroupAmountSpecificationsRespVO> result = BeanUtils.toBean(resultPage, HandlingGroupAmountSpecificationsRespVO.class);
        List<Long> factoryIds = result.getList().stream().map(HandlingGroupAmountSpecificationsRespVO::getFactoryId).distinct().collect(Collectors.toList());
        List<String> dateStrList = result.getList().stream().map(HandlingGroupAmountSpecificationsRespVO::getDateStr).distinct().collect(Collectors.toList());
        List<Long> handlingGroupIds = result.getList().stream().map(HandlingGroupAmountSpecificationsRespVO::getHandlingGroupId).distinct().collect(Collectors.toList());
        if (CollUtil.isNotEmpty(factoryIds) && CollUtil.isNotEmpty(dateStrList) && CollUtil.isNotEmpty(handlingGroupIds)) {
            // -- 工厂 - 时间 - 组
            List<HandlingGroupUserAmountDO> handlingGroupUserAmountDOS = handlingGroupUserAmountService.getByFactorIdAndDateStrAndHandlingGroupId(factoryIds, dateStrList, handlingGroupIds);
            Map<String, List<HandlingGroupUserAmountDO>> map = handlingGroupUserAmountDOS.stream().collect(Collectors.groupingBy(
                    a -> a.getFactoryId() + "-" + a.getDateStr() + "-" + a.getHandlingGroupId()
            ));
            for (HandlingGroupAmountSpecificationsRespVO handlingGroupAmountSpecificationsRespVO : result.getList()) {
                String key = handlingGroupAmountSpecificationsRespVO.getFactoryId() + "-" + handlingGroupAmountSpecificationsRespVO.getDateStr() + "-" + handlingGroupAmountSpecificationsRespVO.getHandlingGroupId();
                handlingGroupAmountSpecificationsRespVO.setHandlingGroupUserAmountItemVOS(BeanUtils.toBean(map.get(key), HandlingGroupUserAmountItemVO.class));
            }
        }
        return result;
    }
}
