package com.bonus.sgzb.material.service.impl;

import com.bonus.sgzb.common.core.exception.ServiceException;
import com.bonus.sgzb.common.core.utils.DateUtils;
import com.bonus.sgzb.common.core.utils.StringUtils;
import com.bonus.sgzb.common.core.web.domain.AjaxResult;
import com.bonus.sgzb.common.security.utils.SecurityUtils;
import com.bonus.sgzb.material.config.ExceptionEnum;
import com.bonus.sgzb.material.config.FieldGenerator;
import com.bonus.sgzb.base.api.domain.MachIneDto;
import com.bonus.sgzb.material.domain.PutInStorageBean;
import com.bonus.sgzb.base.api.domain.SavePutInfoDto;
import com.bonus.sgzb.material.mapper.InventoryAndWarehousingMapper;
import com.bonus.sgzb.material.service.InventoryAndWarehousingService;
import com.bonus.sgzb.material.vo.GlobalContants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author hay
 * @description 入库盘点
 * @date 2024/3/27 13:32
 */
@Service
@Slf4j
public class InventoryAndWarehousingServiceImpl implements InventoryAndWarehousingService {

    @Autowired
    private InventoryAndWarehousingMapper inventoryAndWarehousingMapper;

    /**
     * 查询入库盘点列表
     * @param bean
     * @return
     */
    @Override
    public List<PutInStorageBean> getList(PutInStorageBean bean) {
        return inventoryAndWarehousingMapper.getList(bean);
    }

    /**
     * 生成code编码
     * @return
     */
    public String genderBackCode() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        Date nowDate = DateUtils.getNowDate();
        String format = dateFormat.format(nowDate);
        int taskNum = inventoryAndWarehousingMapper.selectTaskNumByMonth(nowDate) + 1;
        String code = "";
        if (taskNum > GlobalContants.NUM1 && taskNum < GlobalContants.NUM2) {
            code = "PD" + format + "-00" + taskNum;
        } else if (taskNum > GlobalContants.NUM3 && taskNum < GlobalContants.NUM4) {
            code = "PD" + format + "-0" + taskNum;
        } else {
            code = "PD" + format + "-000" + taskNum;
        }
        return code;
    }

    /**
     * 新增入库盘点
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult savePutInfo(SavePutInfoDto dto) {
        log.info("新增入库盘点入参dto：{}", dto);
        Long userId = SecurityUtils.getLoginUser().getUserid();
        dto.setCreator(userId);
        List<String> codeList = new ArrayList<>();
        if (dto.getNum() != null) {
            while (codeList.size() < dto.getNum()) {
                String code = FieldGenerator.generateField();
                int count = selectByCode(code);
                if (count == 0 && !codeList.contains(code)) {
                    codeList.add(code);
                }
            }
        }
        String code = genderBackCode();
        List<MachIneDto> machIneDtoList = dto.getMachIneDtoList();
        //判断提交表单中是否存在相同编码
        for (int i = 0; i < machIneDtoList.size() - 1; i++) {
            for (int j = i + 1; j < machIneDtoList.size(); j++) {
                if (machIneDtoList.get(i).getMaCode().equals(machIneDtoList.get(j).getMaCode())) {
                    throw new ServiceException("列表中包含以下相同的设备编码，请修改后重新提交：" + machIneDtoList.get(i).getMaCode());
                }
            }
        }
        //判断提交中设备编码是否与库中相同
        if (CollectionUtils.isNotEmpty(machIneDtoList)) {
            for (MachIneDto machIneDto : machIneDtoList) {
                if (StringUtils.isNotBlank(machIneDto.getMaCode())) {
                    int count = selectByMaCode(machIneDto.getMaCode());
                    if (count != 0) {
                        throw new ServiceException("以下设备编码与库中数据存在重复，请修改后重新提交：" + machIneDto.getMaCode());
                    }
                }
            }
        }
        int res;
        try {
            //1. 判断是数量还是编号入库，保存到不同表
            //1.1 如果是编号入库
            if (dto.getIsCode()) {
                res = insertMaMachineInfo(dto, codeList, code);
                if (res == 0) {
                    log.error("insertMaMachineInfo方法插入异常");
                    throw new RuntimeException("insertMaMachineInfo方法插入异常");
                }
                //去修改ma_type里面的库存num，根据前端传的数量追加
                res = updateMaTypeInfo(dto.getTypeId(), dto.getNum());
                if (res == 0) {
                    log.error("updateMaTypeInfo方法修改异常");
                    throw new RuntimeException("updateMaTypeInfo方法修改异常");
                }
            } else {
                //2.插入ma_type_put_in_storage_info表和ma_type_put_in_storage_details表
                res = insertPutInfo(dto, code);
                if (res == 0) {
                    log.error("insertPutInfo方法插入异常");
                    throw new RuntimeException("insertPutInfo方法插入异常");
                }
            }
        } catch (Exception e) {
            log.error("保存入库盘点异常:{}",e.getMessage());
            // 添加事务回滚逻辑，保证入库全部成功或者全部失败
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return AjaxResult.error(ExceptionEnum.SAVE_TO_DATABASE.getCode(), ExceptionEnum.SAVE_TO_DATABASE.getMsg());
        }
        return AjaxResult.success(res);
    }

    /**
     * 根据设备编码code查重
     * @param maCode
     * @return
     */
    private int selectByMaCode(String maCode) {
        return inventoryAndWarehousingMapper.selectByMaCode(maCode);
    }


    /**
     * 根据入库单号查看详情
     * @param bean
     * @return
     */
    @Override
    public List<PutInStorageBean> getDetails(PutInStorageBean bean) {
        return inventoryAndWarehousingMapper.getDetails(bean);
    }


    /**
     * 根据code从ma_machine表查询是否有数据，去重
     * @param code
     * @return
     */
    private int selectByCode(String code) {
        return inventoryAndWarehousingMapper.selectByCode(code);
    }

    /**
     * 编号新增，插入ma_machine、ma_machine_label和ma_label_bind
     * @param dto
     * @param code
     * @return
     */
    private int insertMaMachineInfo(SavePutInfoDto dto, List<String> codeList, String code) {
        int res = 0;
        if (dto.getNum() != null) {
            MachIneDto machIneDto = dto.getMachIneDtoList().get(0);
            machIneDto.setCode(code);
            machIneDto.setPutInType(dto.getPutInType());
            machIneDto.setCreator(dto.getCreator());
            machIneDto.setNum(dto.getNum());
            machIneDto.setIsCode(dto.getIsCode());
            machIneDto.setUnitId(dto.getUnitId());
            machIneDto.setProId(dto.getProId());
            machIneDto.setRemarks(dto.getRemarks());
            res += insertInfo(machIneDto);
            machIneDto.setInfoId(machIneDto.getId());
        }
        for (int i = 0; i < dto.getMachIneDtoList().size(); i++) {
            MachIneDto machIneDto = dto.getMachIneDtoList().get(i);
            machIneDto.setCode(code);
            String qrCode = codeList.get(i);
            machIneDto.setQrCode(qrCode);
            machIneDto.setIsCode(dto.getIsCode());
            machIneDto.setTypeId(dto.getTypeId());
            machIneDto.setCreator(dto.getCreator());
            machIneDto.setPutInType(dto.getPutInType());
            machIneDto.setNum(dto.getNum());
            machIneDto.setCheckMan(dto.getCheckMan());
            machIneDto.setUnitId(dto.getUnitId());
            machIneDto.setProId(dto.getProId());
            machIneDto.setInfoId(dto.getMachIneDtoList().get(0).getInfoId());
            res += insertMachineInfo(machIneDto);
        }
        return res;
    }

    /**
     * 插入ma_type_put_in_storage_info表,返回主键id
     * @param machIneDto
     * @return
     */
    private int insertInfo(MachIneDto machIneDto) {
        return inventoryAndWarehousingMapper.saveInfo(machIneDto);
    }

    /**
     * 方法抽取，保持到ma_machine、ma_machine_label和ma_label_bind
     * @param machIneDto
     * @return
     */
    private int insertMachineInfo(MachIneDto machIneDto) {
        int res = inventoryAndWarehousingMapper.insertMachine(machIneDto);
        res += inventoryAndWarehousingMapper.insertMachineLabel(machIneDto);
        res += inventoryAndWarehousingMapper.insertLabelBind(machIneDto);
        res += insertTypePutInStorageInfo(machIneDto);
        return res;
    }

    /**
     * 方法抽取
     * @param machIneDto
     * @return
     */
    private int insertTypePutInStorageInfo(MachIneDto machIneDto) {
        //ma_type_put_in_storage_details表
        return inventoryAndWarehousingMapper.saveDetails(machIneDto);
    }


    /**
     * 方法抽取，追加ma_type表里面的num
     * @param typeId
     * @param num
     * @return
     */
    private int updateMaTypeInfo(String typeId, Double num) {
        return inventoryAndWarehousingMapper.updateMaType(typeId, num);
    }


    /**
     * 插入表方法
     * @param dto
     * @return
     */
    private int insertPutInfo(SavePutInfoDto dto, String code) {
        int res = 0;
        Double total = dto.getMachIneDtoList().stream()
                .map(MachIneDto::getPutInStoreNum)
                .filter(num -> num != null)
                .collect(Collectors.summingDouble(Double::doubleValue));
        if (CollectionUtils.isNotEmpty(dto.getMachIneDtoList())) {
            MachIneDto machIneDto = dto.getMachIneDtoList().get(0);
            machIneDto.setCode(code);
            machIneDto.setPutInType(dto.getPutInType());
            machIneDto.setCreator(dto.getCreator());
            machIneDto.setIsCode(dto.getIsCode());
            machIneDto.setTotalNum(total);
            machIneDto.setUnitId(dto.getUnitId());
            machIneDto.setProId(dto.getProId());
            machIneDto.setRemarks(dto.getRemarks());
            res += insertInfo(machIneDto);
            machIneDto.setInfoId(machIneDto.getId());
        }
        for (int i = 0; i < dto.getMachIneDtoList().size(); i++) {
            MachIneDto machIneDto = dto.getMachIneDtoList().get(i);
            machIneDto.setCreator(dto.getCreator());
            machIneDto.setPutInType(dto.getPutInType());
            machIneDto.setRemarks(dto.getRemarks());
            machIneDto.setUnitId(dto.getUnitId());
            machIneDto.setProId(dto.getProId());
            machIneDto.setCode(code);
            machIneDto.setInfoId(dto.getMachIneDtoList().get(0).getInfoId());
            res += insertTypePutInStorageInfo(machIneDto);
            //根据类型追加ma_type表里面的num
            res += updateMaTypeInfo(machIneDto.getTypeId(), machIneDto.getPutInStoreNum());
        }
        return res;
    }
}
