package com.cf.imes.module.executor.service.optimizeplan;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.cf.imes.module.executor.controller.admin.plan.vo.*;
import com.cf.imes.module.executor.dal.dataobject.goods.GoodsDO;
import com.cf.imes.module.executor.dal.dataobject.orderItem.OrderItemDO;
import com.cf.imes.module.executor.dal.dataobject.plan.PlanDO;
import com.cf.imes.module.executor.dal.dataobject.planitem.PlanItemDO;
import com.cf.imes.module.executor.dal.dataobject.plate.PlateDO;
import com.cf.imes.module.executor.dal.dataobject.remainplaten.OutlineDTO;
import com.cf.imes.module.executor.dal.dataobject.remainplaten.PointDTO;
import com.cf.imes.module.executor.dal.dataobject.remainplaten.RemainPlateDO;
import com.cf.imes.module.executor.dal.mysql.goods.GoodsMapper;
import com.cf.imes.module.executor.dal.mysql.plan.PlanMapper;
import com.cf.imes.module.executor.dal.mysql.plate.PlateMapper;
import com.cf.imes.module.executor.dal.mysql.remainplaten.RemainPlateMapper;
import com.cf.imes.module.executor.util.RectangleChecker;
import com.cf.imes.module.infra.api.file.FileApi;
import com.cf.imes.module.infra.api.file.dto.FileCreateReqDTO;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants.UNKNOWN;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.PLAN_NOT_EXISTS;

/**
 * @author there
 */
@Service
public class OptimizePlanServiceImpl implements OptimizePlanService {

    @Resource
    private PlanMapper planMapper;

    @Resource
    private RemainPlateMapper remainPlateMapper;

    @Resource
    private FileApi fileApi;

    @Resource
    private PlateMapper plateMapper;

    @Resource
    private GoodsMapper goodsMapper;

    @Override
    public List<PlateOptimize> getPlateListByPlanId(Long planId) {
        return planMapper.selectPlateListByPlanId(planId);
    }

    @Override
    public Boolean addRemain(AddRemainReqVO vo) {
        PlanDO planDO = planMapper.selectById(vo.getPlanId());
        if (Objects.isNull(planDO)) {
            throw exception(PLAN_NOT_EXISTS);
        }
        RemainPlateDO remainPlateDO = RemainPlateDO.builder()
                .width(vo.getWidth())
                .length(vo.getLength())
                .planId(vo.getPlanId())
                .initPlanId(vo.getPlanId())
                .goodsId(vo.getGoodsId())
                .name(vo.getGoodsName())
                .material(vo.getMaterial())
                .color(vo.getColor())
                .count(vo.getCount())
                .build();
        remainPlateMapper.insert(remainPlateDO);
        return Boolean.TRUE;
    }

    @Override
    public Boolean savePlanPlateResult(SavePlanPlateResult result) {
        PlanDO planDO = planMapper.selectById(result.getPlanId());
        if (Objects.isNull(planDO)) {
            throw exception(PLAN_NOT_EXISTS);
        }
        try {
            String placeDateFileUrlSource = planDO.getPlaceDateFileUrl();
            String placeOrderFileUrlSource = planDO.getPlaceOrderFileUrl();
            if (StrUtil.isNotBlank(placeDateFileUrlSource)) {
                fileApi.deleteFileByPath(placeDateFileUrlSource).checkError();
            }
            if (StrUtil.isNotBlank(placeOrderFileUrlSource)) {
                fileApi.deleteFileByPath(placeOrderFileUrlSource).checkError();
            }
            FileCreateReqDTO fileCreateReqDTO = new FileCreateReqDTO();

            fileCreateReqDTO.setContent(result.getPlaceData().getBytes());
            fileCreateReqDTO.setName(result.getPlaceData().getOriginalFilename());
            String placeDateFileUrl = fileApi.createFile(fileCreateReqDTO).getCheckedData();

            fileCreateReqDTO.setContent(result.getPlaceOrder().getBytes());
            fileCreateReqDTO.setName(result.getPlaceOrder().getOriginalFilename());
            String placeOrderFileUrl = fileApi.createFile(fileCreateReqDTO).getCheckedData();

            PlanDO updateDO = PlanDO.builder()
                    .id(result.getPlanId())
                    .placeDateFileUrl(placeOrderFileUrl)
                    .placeOrderFileUrl(placeDateFileUrl)
                    .build();
            planMapper.updateById(updateDO);

        } catch (IOException e) {
            throw exception(UNKNOWN);
        }
        return Boolean.TRUE;
    }

    @Override
    public Boolean commit(Long planId) {
        PlanDO planDO = planMapper.selectById(planId);
        if (Objects.isNull(planDO)) {
            throw exception(PLAN_NOT_EXISTS);
        }
        planMapper.updateById(PlanDO.builder()
                .id(planId)
                .status(2)
                .build());
        return Boolean.TRUE;
    }

    @Override
    public OptimizeParamResVO getOptimizeParam(Long planId) {
        //小板列表
        List<PlateParam> plates = plateMapper.selectPlateList(planId);
        //余料规格列表
        List<RemainPlateDO> remainPlateDOS = remainPlateMapper.selectList(new LambdaQueryWrapperX<RemainPlateDO>().eq(RemainPlateDO::getPlanId, planId));
        //余料板规格
        List<OptimizeParamResVO.RawSize> rawSizes = new ArrayList<>();
        List<Integer> remainPlateCount = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(remainPlateDOS)) {
            Map<String, List<OutlineDTO>> map = remainPlateDOS.stream()
                    .map(e -> OutlineDTO.builder()
                            .list(JsonUtils.parseArray(e.getOutline(), PointDTO.class))
                            .length(e.getLength())
                            .width(e.getWidth())
                            .build()
                    )
                    .filter(e -> e.getList().size() == 4 && RectangleChecker.checkRectangle(e.getList()))
                    .collect(Collectors.groupingBy(e -> e.getLength() + "," + e.getWidth()));
            map.entrySet().forEach(e-> {
                String[] split = e.getKey().split(",");
                BigDecimal length = new BigDecimal(split[0]);
                BigDecimal width = new BigDecimal(split[1]);
                List<OutlineDTO> outlines = e.getValue();
                rawSizes.add(OptimizeParamResVO.RawSize.builder()
                                .length(length)
                                .width(width)
                                .x(new BigDecimal(outlines.get(0).getList().get(0).getX()))
                                .y(new BigDecimal(outlines.get(0).getList().get(0).getY()))
                                .build());
                remainPlateCount.add(outlines.size());
            });
        }

        //大板规格
        /**
         * select * from order_goods a
         * left join order_plate b on a.goods_id = b.goods_id
         * left join order_item c on b.id = c.plate_id
         * left join order_plan_item d on c.id = d.item_id
         * where d.plan_id = 1769638780093857792
         */
        MPJLambdaWrapper<GoodsDO> wrapper = new MPJLambdaWrapperX<GoodsDO>()
                .distinct()
                .select(GoodsDO::getId ,GoodsDO::getWidth, GoodsDO::getHeight)
                .leftJoin(PlateDO.class, PlateDO::getGoodsId, GoodsDO::getGoodsId)
                .leftJoin(OrderItemDO.class, OrderItemDO::getPlanId, PlateDO::getPlateNo)
                .leftJoin(PlanItemDO.class, PlanItemDO::getItemId, OrderItemDO::getId);

        GoodsDO goodsDO = goodsMapper.selectJoinOne(GoodsDO.class, wrapper);
        rawSizes.add(OptimizeParamResVO.RawSize.builder()
                        .width(goodsDO.getWidth())
                        .length(goodsDO.getHeight())
                        .x(new BigDecimal("0"))
                        .y(new BigDecimal("0"))
                .build());
        return OptimizeParamResVO.builder()
                .plates(plates)
                .rawSizes(rawSizes)
                .remainPlateCount(remainPlateCount)
                .build();

    }


}
