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

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.FactoryDataDetailRespVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.FactoryDataInfoRespVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.FactoryDataPageReqVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.FactoryDataTotalVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.sizeData.FactoryDataSizeCreateReqVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.sizeData.FactoryDataSizeSaveReqVO;
import cn.iocoder.yudao.module.smartfactory.controller.admin.packagedata.vo.PackageDataCreateReqVO;
import cn.iocoder.yudao.module.smartfactory.convert.packageData.PackageDataConvert;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factorydata.FactoryDataDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factoryinfo.FactoryInfoDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.packagedata.PackageDataDO;
import cn.iocoder.yudao.module.smartfactory.dal.mysql.factorydata.FactoryDataMapper;
import cn.iocoder.yudao.module.smartfactory.service.factoryinfo.FactoryInfoService;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;


/**
 * 工厂出库入库数据 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class FactoryDataServiceImpl implements FactoryDataService {

    @Resource
    private FactoryDataMapper dataMapper;

    @Resource
    @Lazy // 循环依赖，避免报错
    private FactoryDataSizeService dataSizeService;

    @Resource
    private FactoryInfoService factoryInfoService;

    @Override
    public Long createData(List<FactoryDataDO> factoryDataDOS) {

        dataMapper.insertBatch(factoryDataDOS);

        // 返回
        return (long) factoryDataDOS.size();
    }

    @Override
    public void updateData(FactoryDataSizeCreateReqVO updateReqVO) {

        // 修改 规格明细数据
        dataSizeService.updateData(updateReqVO);

        //校验 出入库统计数据是否存在
        List<FactoryDataDO> factoryDataDOS = dataMapper.selectListByFactoryAndDate(updateReqVO.getFactoryId(), updateReqVO.getDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        if (factoryDataDOS != null && !factoryDataDOS.isEmpty()) {

            PackageDataCreateReqVO createReqVO = new PackageDataCreateReqVO();
            createReqVO.setPackageData(updateReqVO.getPackageData());
            createReqVO.setFactoryId(updateReqVO.getFactoryId());
            createReqVO.setPackageDate(updateReqVO.getDate());

            //获得 打包线数据对象
            List<PackageDataDO> packageDataDOS = PackageDataConvert.INSTANCE.convertList(createReqVO);
            // 更新
            factoryDataDOS.forEach(data -> {

                switch (data.getDataType()) {

                    //出库数据
                    case 1:
                        data.setTotalNum(updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getOutNum).sum());
                        data.setDamageNum(updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getOutDamageNum).sum());
                        break;
                    //入库数据
                    case 2:
                        Integer damageNum = packageDataDOS.stream().mapToInt(PackageDataDO::getDamageNum).sum()
                                + updateReqVO.getItems().stream().mapToInt(FactoryDataSizeSaveReqVO::getInDamageNum).sum();

                        data.setTotalNum(packageDataDOS.stream().mapToInt(info -> info.getNum() + info.getAutoNum()).sum());
                        data.setDamageNum(damageNum);
                        data.setSquareNum(packageDataDOS.stream().map(PackageDataDO::getSquareNum).reduce(BigDecimal.ZERO, BigDecimal::add));
                }
            });

            //更新 出入库统计数据
            dataMapper.updateBatch(factoryDataDOS);
        }
    }

    @Override
    public void deleteData(Long factoryId, String date) {

        //删除出入库 规格数据
        dataSizeService.deleteData(factoryId, date);
    }

    @Override
    public FactoryDataDetailRespVO getData(Long factoryId, String date) {

        FactoryDataDetailRespVO respVO = new FactoryDataDetailRespVO();
        respVO.setFactoryId(factoryId);
        respVO.setDate(LocalDate.parse(date));
        respVO.setDamageNum(0);

        // 获得 指定工厂和日期的出入库统计数据
        List<FactoryDataDO> factoryDataDOS = dataMapper.selectListByFactoryAndDate(factoryId, date);
        for (FactoryDataDO factoryDataDO : factoryDataDOS) {

            switch (factoryDataDO.getDataType()) {

                //出库数据
                case 1:
                    respVO.setOutTotalNum(factoryDataDO.getTotalNum());
                    respVO.setDamageNum(respVO.getDamageNum() + factoryDataDO.getDamageNum());
                    break;
                //入库数据
                case 2:
                    respVO.setInTotalNum(factoryDataDO.getTotalNum());
                    respVO.setSquareNum(factoryDataDO.getSquareNum());
                    respVO.setDamageNum(respVO.getDamageNum() + factoryDataDO.getDamageNum());
                    break;
            }
        }

        //获得 规则明细数据
        List<FactoryDataInfoRespVO> infoRespVOS = dataSizeService.getDetailList(factoryId, new LocalDate[]{LocalDate.parse(date), LocalDate.parse(date)});
        respVO.setItems(infoRespVOS);

        return respVO;
    }

    @Override
    public PageResult<FactoryDataDetailRespVO> getDataPage(FactoryDataPageReqVO pageReqVO) {

        //获得 出入库数据分页列表
        IPage<FactoryDataDetailRespVO> mpPage = MyBatisUtils.buildPage(pageReqVO);
        IPage<FactoryDataDetailRespVO> page = dataMapper.selectDetailPage(mpPage, pageReqVO);
        PageResult<FactoryDataDetailRespVO> dataPage = new PageResult<>(page.getRecords(), page.getTotal());

        List<FactoryDataDetailRespVO> respVOS = dataPage.getList();
        if (!respVOS.isEmpty()) {

            //获得工厂信息列表
            List<Long> factoryIdS = respVOS.stream().map(FactoryDataDetailRespVO::getFactoryId).collect(Collectors.toList());
            List<FactoryInfoDO> factoryInfoDOS = factoryInfoService.getFactoryList(factoryIdS);
            Map<Long, FactoryInfoDO> factoryMap = convertMap(factoryInfoDOS, FactoryInfoDO::getId);

            //获得 入库数、打包破损、入库破损、出库数、出库破损的工厂规格数据
            List<FactoryDataInfoRespVO> infoDatas = dataSizeService.getDetailList(pageReqVO.getFactoryId(), pageReqVO.getDate());

            respVOS.forEach(items -> {

                //规格明细数据
                List<FactoryDataInfoRespVO> infoList = infoDatas.stream()
                        .filter(data -> data.getFactoryId().equals(items.getFactoryId()) && data.getDate().equals(items.getDate()))
                        .collect(Collectors.toList());

                items.setItems(infoList);
                items.setFactoryName(factoryMap.get(items.getFactoryId()).getName());

                //移除 已处理过的数据
                infoDatas.removeAll(infoList);
            });

            // 展示当天录入的数据
            if (!infoDatas.isEmpty()) {

                // 按 工厂id和日期 进行分组
                Map<Long, Map<LocalDate, List<FactoryDataInfoRespVO>>> groupedByFactoryIdAndDate = infoDatas.stream()
                        .collect(Collectors.groupingBy(FactoryDataInfoRespVO::getFactoryId,
                                Collectors.groupingBy(FactoryDataInfoRespVO::getDate)));

                groupedByFactoryIdAndDate.forEach((factoryId, dateMap) -> {

                    dateMap.forEach((date, infoList) -> {

                        FactoryDataDetailRespVO dataDetailRespVO = new FactoryDataDetailRespVO();

                        dataDetailRespVO.setId(respVOS.get(0).getId() + 1);
                        dataDetailRespVO.setFactoryId(factoryId);
                        dataDetailRespVO.setFactoryName(factoryMap.get(factoryId).getName());
                        dataDetailRespVO.setDate(date);
                        //设置入库总数
                        dataDetailRespVO.setInTotalNum(infoList.stream().filter(info -> info.getInNum() != null).mapToInt(FactoryDataInfoRespVO::getInNum).sum());
                        //设置入库平方数
                        dataDetailRespVO.setSquareNum(infoList.stream().map(FactoryDataInfoRespVO::getSquareNum).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add));
                        //设置出库总数
                        dataDetailRespVO.setOutTotalNum(infoDatas.stream().filter(info -> info.getOutNum() != null).mapToInt(FactoryDataInfoRespVO::getOutNum).sum());
                        //设置 出入库破损总数
                        dataDetailRespVO.setDamageNum(infoDatas.stream().filter(info -> info.getInDamageNum() != null).mapToInt(info -> info.getInDamageNum() + info.getOutDamageNum()).sum());
                        dataDetailRespVO.setItems(infoList);
                        //设置 可编辑状态
                        dataDetailRespVO.setIsEdit(1);

                        respVOS.add(0, dataDetailRespVO);
                    });
                });
                dataPage.setTotal((long) respVOS.size());
            }
        }

        return dataPage;
    }

    @Override
    public FactoryDataTotalVO getDataTotal() {

        return dataMapper.selectDataSum();
    }

    @Override
    public List<FactoryDataDO> getTodayInboundAndOutboundOverview(Date time) {
        String timeStr = null;
        if (time != null) {
            timeStr = DateUtils.dateFormat(time, "yyyy-MM-dd");
        }
        return dataMapper.selectList(new LambdaQueryWrapperX<FactoryDataDO>()
                .eq(timeStr != null, FactoryDataDO::getDate, timeStr));
    }

    @Override
    public List<FactoryDataDO> getByTimeAndFactoryId(Long factoryId, Date beginDay, Date endDay) {
        return dataMapper.selectList(new LambdaQueryWrapperX<FactoryDataDO>()
                .ge(FactoryDataDO::getDate, beginDay)
                .le(FactoryDataDO::getDate, endDay)
                .eq(FactoryDataDO::getFactoryId, factoryId));
    }

    @Override
    public FactoryDataDO getListByType(Long factoryId, LocalDate date, Integer type) {

        return dataMapper.selectListByType(factoryId, date, type);
    }
}