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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.smartfactory.controller.admin.factorydata.vo.FactoryDataInfoRespVO;
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.factorydata.vo.sizeData.FactoryDataSizeTotalVO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factorydata.FactoryDataDO;
import cn.iocoder.yudao.module.smartfactory.dal.dataobject.factorydata.FactoryDataSizeDO;
import cn.iocoder.yudao.module.smartfactory.dal.mysql.factorydata.FactoryDataSizeMapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.PACKAGE_DATA_EXISTS;
import static cn.iocoder.yudao.module.smartfactory.enums.ErrorCodeConstants.SIZEDATA_NOT_EXISTS;

/**
 * 工厂出库入库规格数据 Service 实现类
 *
 * @author 符溶馨
 */
@Service
@Validated
public class FactoryDataSizeServiceImpl implements FactoryDataSizeService{

    @Resource
    private FactoryDataSizeMapper factoryDataSizeMapper;

    @Resource
    @Lazy // 循环依赖，避免报错
    private FactoryDataService factoryDataService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createData(FactoryDataSizeCreateReqVO createReqVO) throws Exception {

        //校验 当前日期得 入库数据是否已经录入
        if (createReqVO.getType() == 2) {

            Long count = factoryDataSizeMapper.selectCountByType(createReqVO.getFactoryId(), null, createReqVO.getDate(), Arrays.asList(1,4));
            if (count > 0L) {
                throw exception(PACKAGE_DATA_EXISTS);
            }
        }else if (createReqVO.getType() == 1) {  //校验 当前日期得 出库数据是否已经录入

            Long count = factoryDataSizeMapper.selectCountByType(createReqVO.getFactoryId(), null, createReqVO.getDate(), Arrays.asList(2,3));
            if (count > 0L) {
                throw exception(PACKAGE_DATA_EXISTS);
            }
        }

        //校验 当前日期的出库数据是否已经统计过
        FactoryDataDO factoryDataDO = factoryDataService.getListByType(createReqVO.getFactoryId(), createReqVO.getDate(), null);
        if (factoryDataDO != null) {
            throw exception(PACKAGE_DATA_EXISTS);
        }

        //插入
        List<FactoryDataSizeDO> factoryDataSizeDOs = new ArrayList<>();
        for (FactoryDataSizeSaveReqVO reqVO : createReqVO.getItems()) {

            if (reqVO.getInDamageNum() != null) {

                FactoryDataSizeDO dataSizeDO = BeanUtils.toBean(reqVO, FactoryDataSizeDO.class);

                //设置工厂和日期
                dataSizeDO.setFactoryId(createReqVO.getFactoryId());
                dataSizeDO.setDate(createReqVO.getDate());
                //设置入库破损数
                dataSizeDO.setType(1);
                dataSizeDO.setNum(reqVO.getInDamageNum());

                factoryDataSizeDOs.add(dataSizeDO);
            }

            if (reqVO.getOutNum() != null) {

                FactoryDataSizeDO dataSizeDO = BeanUtils.toBean(reqVO, FactoryDataSizeDO.class);

                //设置工厂和日期
                dataSizeDO.setFactoryId(createReqVO.getFactoryId());
                dataSizeDO.setDate(createReqVO.getDate());
                //设置出库数
                dataSizeDO.setType(2);
                dataSizeDO.setNum(reqVO.getOutNum());

                factoryDataSizeDOs.add(dataSizeDO);
            }

            if (reqVO.getOutDamageNum() != null) {

                FactoryDataSizeDO dataSizeDO = BeanUtils.toBean(reqVO, FactoryDataSizeDO.class);

                //设置工厂和日期
                dataSizeDO.setFactoryId(createReqVO.getFactoryId());
                dataSizeDO.setDate(createReqVO.getDate());
                //设置出库破损数
                dataSizeDO.setType(3);
                dataSizeDO.setNum(reqVO.getOutDamageNum());

                factoryDataSizeDOs.add(dataSizeDO);
            }

            if (reqVO.getInNum() != null || reqVO.getSquareNum() != null) {

                FactoryDataSizeDO dataSizeDO = BeanUtils.toBean(reqVO, FactoryDataSizeDO.class);

                //设置工厂和日期
                dataSizeDO.setFactoryId(createReqVO.getFactoryId());
                dataSizeDO.setDate(createReqVO.getDate());
                //设置入库数
                dataSizeDO.setType(4);
                dataSizeDO.setNum(reqVO.getInNum());
                try {

                    if (reqVO.getSizeName().contains("*")) {
                        dataSizeDO.setNum(
                                reqVO.getSquareNum() != null ? Integer.parseInt(factoryDataService.convertSquare(reqVO.getSquareNum(), 2, reqVO.getSizeName())) : reqVO.getInNum()
                        );
                        dataSizeDO.setSquareNum(
                                reqVO.getInNum() != null ? new BigDecimal(factoryDataService.convertSquare(reqVO.getInNum(), 1, reqVO.getSizeName())) : reqVO.getSquareNum()
                        );
                    }else {
                        dataSizeDO.setNum(reqVO.getInNum());
                        dataSizeDO.setSquareNum(reqVO.getSquareNum());
                    }
                } catch (Exception ex) {
                    throw new Exception(ex);
                }

                factoryDataSizeDOs.add(dataSizeDO);
            }
        }

        factoryDataSizeMapper.insertBatch(factoryDataSizeDOs);

        return (long) factoryDataSizeDOs.size();
    }

    @Override
    public void updateData(FactoryDataSizeCreateReqVO updateReqVO) throws Exception {

        // 更新
        List<FactoryDataSizeDO> createSizeDos = new ArrayList<>();
        List<FactoryDataSizeDO> factoryDataSizeDOs = new ArrayList<>();
        for (FactoryDataSizeSaveReqVO reqVO : updateReqVO.getItems()) {

            if (reqVO.getInNum() != null || reqVO.getSquareNum() != null) {

                FactoryDataSizeDO dataSizeDO = new FactoryDataSizeDO();

                //设置入库数
                dataSizeDO.setId(reqVO.getInNumId());
                try {

                    if (reqVO.getSizeName().contains("*")) {
                        dataSizeDO.setNum(
                                reqVO.getSquareNum() != null ? Integer.parseInt(factoryDataService.convertSquare(reqVO.getSquareNum(), 2, reqVO.getSizeName())) : reqVO.getInNum()
                        );
                        dataSizeDO.setSquareNum(
                                reqVO.getInNum() != null ? new BigDecimal(factoryDataService.convertSquare(reqVO.getInNum(), 1, reqVO.getSizeName())) : reqVO.getSquareNum()
                        );
                    }else {
                        dataSizeDO.setNum(reqVO.getInNum());
                        dataSizeDO.setSquareNum(reqVO.getSquareNum());
                    }
                } catch (Exception ex) {
                    throw new Exception(ex);
                }

                if (reqVO.getInNumId() == null) {

                    dataSizeDO.setFactoryId(updateReqVO.getFactoryId());
                    dataSizeDO.setDate(updateReqVO.getDate());
                    dataSizeDO.setSizeId(reqVO.getSizeId());
                    dataSizeDO.setSizeName(reqVO.getSizeName());
                    dataSizeDO.setType(4);
                    createSizeDos.add(dataSizeDO);
                }else {
                    factoryDataSizeDOs.add(dataSizeDO);
                }
            }

            if (reqVO.getInDamageNum() != null) {

                FactoryDataSizeDO dataSizeDO = new FactoryDataSizeDO();

                //设置入库破损数
                dataSizeDO.setId(reqVO.getInDamageNumId());
                dataSizeDO.setNum(reqVO.getInDamageNum());

                if (reqVO.getInDamageNumId() == null) {

                    dataSizeDO.setFactoryId(updateReqVO.getFactoryId());
                    dataSizeDO.setDate(updateReqVO.getDate());
                    dataSizeDO.setSizeId(reqVO.getSizeId());
                    dataSizeDO.setSizeName(reqVO.getSizeName());
                    dataSizeDO.setType(1);
                    createSizeDos.add(dataSizeDO);
                }else {
                    factoryDataSizeDOs.add(dataSizeDO);
                }
            }

            if (reqVO.getOutNum() != null) {

                FactoryDataSizeDO dataSizeDO = new FactoryDataSizeDO();

                //设置出库数
                dataSizeDO.setId(reqVO.getOutNumId());
                dataSizeDO.setNum(reqVO.getOutNum());

                if (dataSizeDO.getId() == null) {

                    dataSizeDO.setFactoryId(updateReqVO.getFactoryId());
                    dataSizeDO.setDate(updateReqVO.getDate());
                    dataSizeDO.setSizeId(reqVO.getSizeId());
                    dataSizeDO.setSizeName(reqVO.getSizeName());
                    dataSizeDO.setType(2);
                    createSizeDos.add(dataSizeDO);
                }else {
                    factoryDataSizeDOs.add(dataSizeDO);
                }
            }

            if (reqVO.getOutDamageNum() != null) {

                FactoryDataSizeDO dataSizeDO = new FactoryDataSizeDO();

                //设置出库破损数
                dataSizeDO.setId(reqVO.getOutDamageNumId());
                dataSizeDO.setNum(reqVO.getOutDamageNum());

                if (dataSizeDO.getId() == null) {

                    dataSizeDO.setFactoryId(updateReqVO.getFactoryId());
                    dataSizeDO.setDate(updateReqVO.getDate());
                    dataSizeDO.setSizeId(reqVO.getSizeId());
                    dataSizeDO.setSizeName(reqVO.getSizeName());
                    dataSizeDO.setType(3);
                    createSizeDos.add(dataSizeDO);
                }else {
                    factoryDataSizeDOs.add(dataSizeDO);
                }
            }
        }

        // 处理删除的数据
        List<Long> deleteIds = updateReqVO.getDeleteItems().stream()
                .flatMap(item -> Stream.of(item.getInNumId(), item.getInDamageNumId(), item.getOutNumId(), item.getOutDamageNumId()))
                .filter(ObjectUtil::isNotNull)
                .collect(Collectors.toList());

        if (!factoryDataSizeDOs.isEmpty()) {
            factoryDataSizeMapper.updateBatch(factoryDataSizeDOs);
        }

        if (!createSizeDos.isEmpty()) {
            factoryDataSizeMapper.insertBatch(createSizeDos);
        }

        if (CollectionUtil.isNotEmpty(deleteIds)) {
            factoryDataSizeMapper.deleteBatchIds(deleteIds);
        }

    }

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

        LocalDateTime[] dateTimes = {LocalDateTime.now().with(LocalTime.MIN), LocalDateTime.now().with(LocalTime.MAX)};

        //校验是否 为当天数据
        Long count = factoryDataSizeMapper.selectCountByFactoryId(factoryId, date, dateTimes);
        if (count == 0L) {
            throw exception(SIZEDATA_NOT_EXISTS);
        }

        // 删除
        factoryDataSizeMapper.deleteByFactoryId(factoryId, date);
    }

    @Override
    public List<FactoryDataInfoRespVO> getDetailList(Long factoryId, LocalDate[] date, LocalDateTime[] createTime) {

        return factoryDataSizeMapper.selectDetailList(factoryId, date, createTime);
    }

    @Override
    public List<FactoryDataInfoRespVO> getSUMByDateTimes(LocalDateTime[] dateTimes) {

        return factoryDataSizeMapper.selectSUMByDateTimes(dateTimes);
    }

    @Override
    public List<FactoryDataSizeDO> getLastSize(Long factoryId, List<Integer> dataTypes) {

        return factoryDataSizeMapper.selectLastSize(factoryId, dataTypes);
    }

    @Override
    public List<FactoryDataSizeTotalVO> getSizeTotalByFactory(Long factoryId, LocalDate[] date) {

        return factoryDataSizeMapper.selectSizeDataSumByFactory(factoryId, date);
    }
}
