/**
 * 文件：MateriaServiceImpl.java 版本：1.0.0 日期： Copyright &reg; All right reserved.
 */

package com.mortals.xhx.module.materia.service.impl;

import com.mortals.framework.common.code.YesNo;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.framework.util.DataUtil;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.param.service.ParamService;
import com.mortals.xhx.base.system.upload.service.UploadService;
import com.mortals.xhx.common.code.BomStatusEnum;
import com.mortals.xhx.common.excel.core.ExcelUtils;
import com.mortals.xhx.common.excel.core.IExcelUtil;
import com.mortals.xhx.common.key.Constant;
import com.mortals.xhx.common.key.ParamKey;
import com.mortals.xhx.common.utils.BeanUtil;
import com.mortals.xhx.module.materia.dao.MateriaDao;
import com.mortals.xhx.module.materia.model.*;
import com.mortals.xhx.module.materia.service.*;
import com.mortals.xhx.module.supplier.model.SupplierEntity;
import com.mortals.xhx.module.supplier.model.SupplierQuery;
import com.mortals.xhx.module.supplier.service.SupplierService;
import org.apache.http.entity.ContentType;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * Title: 物料主表
 * </p>
 * <p>
 * Description: MateriaServiceImpl service接口
 * </p>
 * <p>
 * Copyright: Copyright &reg;
 * </p>
 * <p>
 * Company:
 * </p>
 *
 * @author
 * @version 1.0.0
 */
@Service("materiaService")
public class MateriaServiceImpl extends AbstractCRUDServiceImpl<MateriaDao, MateriaEntity, Long>
        implements MateriaService {

    @Autowired
    private MateriaCategoryService materiaCategoryService;
    @Autowired
    private ParamService paramService;
    @Value("${upload.path}")
    private String filePath;
    @Autowired
    private UploadService uploadService;

    @Autowired
    private MateriaBomService materiaBomService;
    @Autowired
    private MateriaBomItemService materiaBomItemService;
    @Autowired
    private SupplierService supplierService;
    @Autowired
    private MateriaSupplierService materiaSupplierService;


    @Override
    protected void saveBefore(MateriaEntity entity, Context context) throws AppException {
        setMateriaCode(entity, context);
        super.saveBefore(entity, context);
    }

    @Override
    protected void updateBefore(MateriaEntity entity, Context context) throws AppException {

        //校验当前物料是否有关联的bom单 并且有审核 如果有则不能修改

        MateriaBomQuery materiaBomQuery = new MateriaBomQuery();
        materiaBomQuery.setMateriaId(entity.getId());

        MateriaBomEntity materiaBomEntity = materiaBomService.find(materiaBomQuery, context).stream().filter(f ->
                f.getStatus().equals(BomStatusEnum.BOM_PUBLISH.getValue()) || f.getStatus().equals(BomStatusEnum.BOM_AUDIT.getValue())
        ).findAny().orElseGet(() -> null);

        if (!ObjectUtils.isEmpty(materiaBomEntity)) {
            throw new AppException(String.format("当前物料存在关联的BOM:%s已发布或审核中，不能修改！", materiaBomEntity.getCode()));
        }

        MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
        materiaBomItemQuery.setMateriaId(entity.getId());
        materiaBomItemService.find(materiaBomItemQuery, context).stream().peek(item -> {
            MateriaBomEntity bomEntity = materiaBomService.get(item.getBomId(), context);
            if (bomEntity.getStatus().equals(BomStatusEnum.BOM_PUBLISH.getValue()) || bomEntity.getStatus().equals(BomStatusEnum.BOM_AUDIT.getValue())) {
                throw new AppException(String.format("当前物料存在关联的BOM:%s已发布或审核中，不能修改！", bomEntity.getCode()));
            }
        }).count();


        super.updateBefore(entity, context);
    }

    @Override
    protected void updateAfter(MateriaEntity entity, Context context) throws AppException {

        MateriaBomQuery bomQuery = new MateriaBomQuery();
        bomQuery.setMateriaId(entity.getId());
        bomQuery.setStatus(BomStatusEnum.BOM_EDIT.getValue());

        MateriaBomEntity bomEntity = new MateriaBomEntity();
        bomEntity.setMateriaName(entity.getName());
        materiaBomService.updateBatch(bomEntity, bomQuery, context);

        MateriaBomItemQuery materiaBomItemQuery = new MateriaBomItemQuery();
        materiaBomItemQuery.setMateriaId(entity.getId());

        MateriaBomItemEntity bomItemEntity = new MateriaBomItemEntity();
        bomItemEntity.setMateriaName(entity.getName());

        materiaBomItemService.updateBatch(bomItemEntity, materiaBomItemQuery, context);


        super.updateAfter(entity, context);
    }

    /**
     * 生成物料代码
     *
     * @param entity
     * @param context
     * @return
     */
    private void setMateriaCode(MateriaEntity entity, Context context) {
        //获取物料编码长度
        String lens = paramService.getValueByKey(ParamKey.MATERIA_CODE_LENGTH);
        if (ObjectUtils.isEmpty(lens)) {
            lens = Constant.Param_MateriaDefaultLens;
        }
        //获取当前类目启始数
        MateriaCategoryEntity category = materiaCategoryService.get(entity.getCategoryId(), true);
        Integer startNum = category.getStartNum();
        startNum++;
        int length = String.valueOf(startNum).length();
        if (length > Integer.parseInt(lens)) {
            throw new AppException(String.format("当前物料编码已超过最大编码长度，code:%s, maxlens:%s", startNum, lens));
        }

        //根据物料编码长度自动补0
        String selfCode = StringUtils.lpad(startNum, Integer.parseInt(lens));
        entity.setSelfCode(selfCode);
        entity.setCode(category.getCode() + "." + entity.getSelfCode());

        //校验生成的code是否唯一，如果已经存在则累加重新检查
        startNum = checkCodeExist(entity, context, startNum, lens, category.getCode());


        category.setStartNum(startNum);
        materiaCategoryService.update(category, context);
        context.setAttribute("isAdd", true);
    }

    private Integer checkCodeExist(MateriaEntity entity, Context context, Integer startNum, String lens, String code) {
        MateriaQuery materiaQuery = new MateriaQuery();
        materiaQuery.setCode(entity.getCode());
        int count = this.count(materiaQuery, context);
        if (count > 0) {
            startNum++;
            int length = String.valueOf(startNum).length();
            if (length > Integer.parseInt(lens)) {
                throw new AppException(String.format("当前物料编码已超过最大编码长度，code:%s, maxlens:%s", startNum, lens));
            }

            //根据物料编码长度自动补0
            String selfCode = StringUtils.lpad(startNum, Integer.parseInt(lens));
            entity.setSelfCode(selfCode);
            entity.setCode(code + "." + entity.getSelfCode());
            return checkCodeExist(entity, context, startNum, lens, code);
        }
        return startNum;
    }

    @Override
    protected void validData(MateriaEntity entity, Context context) throws AppException {
        MateriaQuery query = new MateriaQuery();
        query.setCategoryId(entity.getCategoryId());
        query.setName(entity.getName());
        if (null != context.getAttribute("isAdd")) {// 新增
            if (this.count(query, context) > 0) {
                throw new AppException(String.format("同一类目下物料名称不能重复, categoryId:%s, name:%s", entity.getCategoryId(), entity.getName()));
            }
        } else if (null == context.getAttribute("isAdd")) {// 编辑
            List<MateriaEntity> list = this.find(query, context);
            for (MateriaEntity materiaEntity : list) {
                if (!materiaEntity.getId().equals(entity.getId().longValue())) {
                    throw new AppException(String.format("同一类目下物料名称不能重复, categoryId:%s, name:%s", entity.getCategoryId(), entity.getName()));
                }
            }
        }
        if (StringUtils.isNotEmpty(entity.getAssetsCode()) && entity.getAssetsCode().length() != 2) {
            throw new AppException("资产编码为两位数字");
        }

        //判断损失率为0-100
        if (entity.getLossRate() < 0 || entity.getLossRate() > 100) {
            throw new AppException("损耗率只能在0-100，当前损耗率为:" + entity.getLossRate());
        }

        if(BeanUtil.isConSpeChar(entity.getName())){
            throw new AppException("物料名称包含非法字符:" + entity.getName());

        }


        super.validData(entity, context);
    }

    @Override
    public String doImportExcel(String path, Context context) {

        String rootPath = this.filePath.endsWith("/") ? this.filePath : this.filePath + "/";
        String filePath = rootPath + (StringUtils.isEmpty(path) ? "" : path + "/");

        StringBuilder returnStr = new StringBuilder();
        returnStr.append("<div style=\"height:500px;overflow:scroll\">");

        Map<String, String> matriaUnitOfMeasureMap = paramService.getParamByFirstOrganize("MatriaUnitOfMeasure");
        Map<String, String> matriaSupplyTypeMap = paramService.getParamByFirstOrganize("MatriaSupplyType");

        String lens = paramService.getValueByKey(ParamKey.MATERIA_CODE_LENGTH);
        if (ObjectUtils.isEmpty(lens)) {
            lens = Constant.Param_MateriaDefaultLens;
        }

        int suc = 0;
        int fail = 0;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filePath);
            IExcelUtil<MateriaImport> util = new ExcelUtils<>();//创建excel工具类

            List<MateriaImport> list = util.build(MateriaImport.class).importExcel("materia",path,fis);// 导入

            list = list.stream().sorted(Comparator.comparing(MateriaImport::getRowNum)).collect(Collectors.toList());

            for (MateriaImport materiaImport : list) {
                MateriaEntity materiaEntity = new MateriaEntity();
                materiaEntity.initAttrValue();
                BeanUtils.copyProperties(materiaImport, materiaEntity);

                Double v = Double.parseDouble(materiaImport.getCode());
                //查询类目编码
                MateriaCategoryQuery categoryQuery = new MateriaCategoryQuery();
                categoryQuery.setCode(v.intValue() + "");
                MateriaCategoryEntity categoryEntity = materiaCategoryService.find(categoryQuery, context).stream().findFirst().orElseGet(() -> null);
                if (ObjectUtils.isEmpty(categoryEntity)) {
                    returnStr.append(String.format("当前物料类目编码不存在:%s", materiaImport.getCode()));
                    returnStr.append("<br/>");
                    returnStr.append("<br/>");
                    fail++;
                    continue;
                }

                if (!checkParams(returnStr, materiaImport, fail)) continue;
                String keyByLoop = getKeyByLoop(matriaUnitOfMeasureMap, materiaImport.getUnitOfMeasureName());
                if (ObjectUtils.isEmpty(keyByLoop)) {
                    returnStr.append(String.format("当前物料计量单位编码不存在:%s", materiaImport.getUnitOfMeasureName()));
                    returnStr.append("<br/>");
                    returnStr.append("<br/>");
                    fail++;
                    continue;
                }

                materiaEntity.setUnitOfMeasure(Long.parseLong(keyByLoop));
                String supplyKey = getKeyByLoop(matriaSupplyTypeMap, materiaImport.getSupplyTypeName());
                if (ObjectUtils.isEmpty(supplyKey)) {
                    returnStr.append(String.format("当前物料补给方式编码不存在:%s", materiaImport.getSupplyTypeName()));
                    returnStr.append("<br/>");
                    returnStr.append("<br/>");
                    fail++;
                    continue;
                }


                materiaEntity.setSupplyType(Integer.parseInt(supplyKey));
                //转换计划成本
                materiaEntity.setCostPlan(Math.round(DataUtil.converStr2Double(materiaImport.getCostPlan(), 0.0) * 1000));
                materiaEntity.setLossRate(((Double) Double.parseDouble(materiaImport.getLossRate())).intValue());
                materiaEntity.setUseNum(((Double) Double.parseDouble(materiaImport.getUseNum())).longValue());
                //保存图片
                materiaEntity.setCategoryId(categoryEntity.getId());
                materiaEntity.setEnabled(YesNo.YES.getValue());
                materiaEntity.setCreateUser(context.getUser().getRealName());
                materiaEntity.setCreateTime(new Date());
                materiaEntity.setUpdateTime(new Date());
                materiaEntity.setUpdateUser(context.getUser().getRealName());

                MateriaQuery query = new MateriaQuery();
                query.setCategoryId(materiaEntity.getCategoryId());
                query.setName(materiaEntity.getName());

                if (this.count(query, context) > 0) {
                    returnStr.append(String.format("同一类目下物料名称不能重复, 类目编码:%s, 物料名称:%s", materiaEntity.getCategoryId(), materiaEntity.getName()));
                    returnStr.append("<br/>");
                    returnStr.append("<br/>");
                    fail++;
                    continue;
                }

                //获取当前类目启始数
                Integer startNum = categoryEntity.getStartNum();
                startNum++;
                int length = String.valueOf(startNum).length();
                if (length > Integer.parseInt(lens)) {
                    returnStr.append(String.format("当前物料编码已超过最大编码长度，code:%s, maxlens:%s", startNum, lens));
                    returnStr.append("<br/>");
                    returnStr.append("<br/>");
                    fail++;
                    continue;
                }
                //根据物料编码长度自动补0
                materiaEntity.setSelfCode(StringUtils.lpad(startNum, Integer.parseInt(lens)));
                materiaEntity.setCode(categoryEntity.getCode() + "." + materiaEntity.getSelfCode());
                startNum = checkCodeExist(materiaEntity, context, startNum, lens, categoryEntity.getCode());

                categoryEntity.setStartNum(startNum);
                materiaCategoryService.update(categoryEntity, context);
                InputStream inputStream = new ByteArrayInputStream(materiaImport.getPicObj().getData());
         /*       try {
                    MultipartFile file = new MockMultipartFile(ContentType.APPLICATION_OCTET_STREAM.toString(), "1." + materiaImport.getPicObj().suggestFileExtension(), materiaImport.getPicObj().getMimeType(), inputStream);
                    String picImg = uploadService.saveFileUpload(file, "/image/plm/materia", context.getUser());
                    materiaEntity.setMainPicUrl(picImg);
                } catch (IOException e) {
                    e.printStackTrace();
                }
*/
                this.getDao().insert(materiaEntity);
                //添加供应商
                if (!ObjectUtils.isEmpty(materiaImport.getSupplyName())) {
                    SupplierQuery supplierQuery = new SupplierQuery();
                    supplierQuery.setName(materiaImport.getSupplyName());
                    SupplierEntity supplierEntity = supplierService.find(supplierQuery, context).stream().findAny().orElseGet(() -> null);
                    if (!ObjectUtils.isEmpty(supplierEntity)) {
                        MateriaSupplierEntity materiaSupplierEntity = new MateriaSupplierEntity();
                        materiaSupplierEntity.initAttrValue();
                        materiaSupplierEntity.setMateriaId(materiaEntity.getId());
                        materiaSupplierEntity.setSupplierId(supplierEntity.getId());
                        materiaSupplierEntity.setCostPlan(materiaEntity.getCostPlan());
                        materiaSupplierEntity.setDeliveryPeriod(1L);
                        materiaSupplierEntity.setUnitOfMeasure(100L);
                        materiaSupplierEntity.setDeliveryPeriodUnit(30);
                        materiaSupplierEntity.setCreateTime(new Date());
                        materiaSupplierEntity.setCreateUser(context.getUser().getRealName());
                        materiaSupplierEntity.setUpdateTime(new Date());
                        materiaSupplierEntity.setUpdateUser(context.getUser().getRealName());

                        materiaSupplierService.save(materiaSupplierEntity, context);
                    }
                }
                suc++;
            }

            returnStr.append(String.format("物料导入成功：%s条", suc));
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            if (fail > 0) {
                returnStr.append(String.format("物料导入失败：%s条", fail));
            }
            returnStr.append("</div>");



        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        return returnStr.toString();
    }


    private boolean checkParams(StringBuilder returnStr, MateriaImport materiaImport, Integer fail) {
        if (ObjectUtils.isEmpty(materiaImport.getLossRate())) {
            returnStr.append("当前物料损耗率为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if (ObjectUtils.isEmpty(materiaImport.getName())) {
            returnStr.append("当前物料名称为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }


        if (ObjectUtils.isEmpty(materiaImport.getCostPlan())) {
            returnStr.append("当前物料计划成本为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if (ObjectUtils.isEmpty(materiaImport.getSupplyTypeName())) {
            returnStr.append("当前物料补给方式为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if (ObjectUtils.isEmpty(materiaImport.getUnitOfMeasureName())) {
            returnStr.append("当前物料计量单位为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if (ObjectUtils.isEmpty(materiaImport.getSpecModel())) {
            returnStr.append("当前物料规格型号为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if (ObjectUtils.isEmpty(materiaImport.getUseNum())) {
            returnStr.append("当前物料默认用量为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }


        if (ObjectUtils.isEmpty(materiaImport.getLossRate())) {
            returnStr.append("当前物料损耗率为空！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }


        double data = DataUtil.converStr2Double(materiaImport.getUseNum(), -1.0);
        if (data == -1.0) {
            returnStr.append("当前默认用量为非数字 userNum:" + materiaImport.getUseNum() + "！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        data = DataUtil.converStr2Double(materiaImport.getLossRate(), -1.0);
        if (data == -1.0) {
            returnStr.append("当前物料损耗率为非数字 lossRate:" + materiaImport.getLossRate() + "！rowNum:" + materiaImport.getRowNum());
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        //判断损失率为0-100
        if (data < 0 || data > 100) {
            returnStr.append("损耗率只能在0-100，当前损耗率为:" + data);
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }


        //检查是否有图片
        if (ObjectUtils.isEmpty(materiaImport.getPicObj())) {
            returnStr.append(String.format("当前物料:%s行未发现物料图片，rowNum:%s,请重新编辑excel确保每行图片列单元格包含一张物料图片！", materiaImport.getName(), materiaImport.getRowNum()));
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if(BeanUtil.isConSpeChar(materiaImport.getName())){
            returnStr.append(String.format("物料名称包含非法字符:%s", materiaImport.getName()));
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }

        if(materiaImport.getName().length()>50){
            returnStr.append(String.format("物料名称最大不能超过50个字符:%s", materiaImport.getName()));
            returnStr.append("<br/>");
            returnStr.append("<br/>");
            fail++;
            return false;
        }


        return true;
    }

    @Override
    public void discardMateria(Long id, Context context) {
        MateriaEntity materiaEntity = this.get(id, context);
        materiaEntity.setEnabled(YesNo.NO.getValue());

        this.getDao().update(materiaEntity);
    }

    @Override
    public void updateAsset(Long id, String asset, Context context) {
        MateriaEntity materiaEntity = this.get(id, context);
        materiaEntity.setAssetsCode(asset);
        this.getDao().update(materiaEntity);
    }


    private <K, V> K getKeyByLoop(Map<K, V> map, V value) {
        for (Map.Entry<K, V> entry : map.entrySet()) {
            if (Objects.equals(entry.getValue(), value)) {
                return entry.getKey();
            }
        }
        return null;
    }

    public static void main(String[] args) {
        System.out.println(StringUtils.lpad(10, 4));


        System.out.println(((Double) Double.parseDouble("3.0")).intValue());
    }

    @Override
    public List<Map> getBomInfoByAssetCode(String assetCode) {
        Map<String, Object> param = new HashMap<>();
        ;
        param.put("assetsCode", assetCode.substring(0, 2));
        List<Map> list = dao.getBomInfoByAssetCode(param);
        return list;
    }
}

