package com.fjhx.mes.service.production.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.mes.entity.applicable.po.ApplicableProducts;
import com.fjhx.mes.entity.bom.po.BomDetail;
import com.fjhx.mes.entity.bom.po.BomInfo;
import com.fjhx.mes.entity.production.dto.ProductionTaskDto;
import com.fjhx.mes.entity.production.dto.ProductionTaskSelectDto;
import com.fjhx.mes.entity.production.po.*;
import com.fjhx.mes.entity.production.vo.ProductionTaskDetailVo;
import com.fjhx.mes.entity.production.vo.ProductionTaskVo;
import com.fjhx.mes.entity.technology.po.Technology;
import com.fjhx.mes.entity.work.po.WorkOrder;
import com.fjhx.mes.entity.work.po.WorkOrderBom;
import com.fjhx.mes.entity.work.po.WorkOrderProductionProcesses;
import com.fjhx.mes.mapper.production.ProductionTaskMapper;
import com.fjhx.mes.service.applicable.ApplicableProductsService;
import com.fjhx.mes.service.bom.BomDetailService;
import com.fjhx.mes.service.bom.BomInfoService;
import com.fjhx.mes.service.production.*;
import com.fjhx.mes.service.technology.TechnologyService;
import com.fjhx.mes.service.work.WorkOrderBomService;
import com.fjhx.mes.service.work.WorkOrderProductionProcessesService;
import com.fjhx.mes.service.work.WorkOrderService;
import com.fjhx.mes.utils.code.CodeEnum;
import com.fjhx.wms.entity.stock.emums.StockWaitType;
import com.fjhx.wms.entity.stock.po.StockWait;
import com.fjhx.wms.entity.stock.po.StockWaitDetails;
import com.fjhx.wms.service.stock.StockWaitDetailsService;
import com.fjhx.wms.service.stock.StockWaitService;
import com.obs.services.internal.ServiceException;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.system.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 生产任务 服务实现类
 * </p>
 *
 * @author
 * @since 2023-03-30
 */
@Service
public class ProductionTaskServiceImpl extends ServiceImpl<ProductionTaskMapper, ProductionTask> implements ProductionTaskService {
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private ProductionPlanService productionPlanService;
    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private BomInfoService bomInfoService;
    @Autowired
    private BomDetailService bomDetailService;
    @Autowired
    private StockWaitService stockWaitService;
    @Autowired
    private StockWaitDetailsService stockWaitDetailsService;
    @Autowired
    private WorkOrderBomService workOrderBomService;
    @Autowired
    private WorkOrderProductionProcessesService workOrderProductionProcessesService;
    @Autowired
    private TechnologyService technologyService;
    @Autowired
    private ApplicableProductsService applicableProductsService;
    @Autowired
    private ProductionTaskDetailService productionTaskDetailService;
    @Autowired
    private ProductionProcessesService productionProcessesService;
    @Autowired
    private ProductionTaskDetailRecordService productionTaskDetailRecordService;

    @Override
    public Page<ProductionTaskVo> getPage(ProductionTaskSelectDto dto) {
        IWrapper<ProductionTask> wrapper = getWrapper();
        wrapper.orderByDesc("pt", ProductionTask::getId);
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            wrapper.and(q -> q.like("pt", ProductionTaskVo::getCode, dto.getKeyword())
                    .or().like("pt", ProductionTaskVo::getQuantity, dto.getKeyword())
                    .or().like("pt", ProductionTaskVo::getDueDate, dto.getKeyword()));
        }
        Page<ProductionTaskVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<ProductionTaskVo> records = page.getRecords();
        //赋值产品名称
        List<Long> productIds = records.stream().map(ProductionTaskVo::getProductId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(productIds)) {
            List<ProductInfo> productInfos = productInfoService.listByIds(productIds);
            Map<Long, ProductInfo> productInfoMap = productInfos.stream().collect(Collectors.groupingBy(ProductInfo::getId,
                    Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))));
            for (ProductionTaskVo productionTaskVo : records) {
                Long productId = productionTaskVo.getProductId();
                if (ObjectUtil.isNotEmpty(productId)) {
                    ProductInfo productInfo = productInfoMap.get(productId);
                    if (ObjectUtil.isNotEmpty(productInfo)) {
                        productionTaskVo.setProductName(productInfo.getName());
                    }
                }
            }
        }

        //赋值负责人名字
        UserUtil.assignmentNickName(records, ProductionTask::getPersonLiableId, ProductionTaskVo::setPersonLiableName);
        return page;
    }

    @Override
    public ProductionTaskVo detail(Long id) {
        ProductionTaskVo productionTaskVo = baseMapper.detail(id);
        ProductInfo productInfo = productInfoService.getById(productionTaskVo.getProductId());
        if (ObjectUtil.isNotEmpty(productInfo)) {
            productionTaskVo.setProductName(productInfo.getName());
        }
        Map<Long, String> nickNameMapByIds = UserUtil.getNickNameMapByIds(Arrays.asList(productionTaskVo.getPersonLiableId()));
        if (ObjectUtil.isNotEmpty(nickNameMapByIds)) {
            productionTaskVo.setPersonLiableName(nickNameMapByIds.get(productionTaskVo.getPersonLiableId()));
        }
        return productionTaskVo;
    }

    @DSTransactional
    @Override
    public void add(ProductionTaskDto productionTaskDto) {
        productionTaskDto.setCode(CodeEnum.PRODUCTION_TASK.getCode());
        this.save(productionTaskDto);
        Long productionPlanId = productionTaskDto.getProductionPlanId();
        //更新生产计划状态为进行中
        ProductionPlan productionPlan = productionPlanService.getById(productionPlanId);
        productionPlan.setStatus(1);
        productionPlanService.updateById(productionPlan);

        //根据工单是否是定制工单 创建BOM待出库数据
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());
        if (ObjectUtil.isEmpty(workOrder)) {
            throw new ServiceException("查询不到该任务的工单信息");
        }

        List<BomDetail> bomDetailList = new ArrayList<>();
        if ("1".equals(workOrder.getIsCustomized())) {
            List<WorkOrderBom> workOrderBomList = workOrderBomService.list(q -> q.eq(WorkOrderBom::getWorkOrderId, workOrder.getId()));
            if (ObjectUtil.isEmpty(workOrderBomList)) {
                throw new ServiceException("该工单为定制工单 未配置定制BOM");
            }
            bomDetailList = BeanUtil.copyToList(workOrderBomList, BomDetail.class);
        } else {
            //查询BOM信息
            BomInfo bomInfo = bomInfoService.getOne(q -> q.eq(BomInfo::getProductId, workOrder.getProductId()).eq(BomInfo::getCurrentVersion,1));
            if (ObjectUtil.isEmpty(bomInfo)) {
                throw new ServiceException("查询不到产品的BOM信息");
            }
            bomDetailList = bomDetailService.list(q -> q.eq(BomDetail::getBomInfoId, bomInfo.getId()));
            if (ObjectUtil.isEmpty(bomDetailList)) {
                throw new ServiceException("查询不到BOM明细");
            }
        }
        //创建待出库信息
        StockWait stockWait = new StockWait();
        stockWait.setBusinessId(productionTaskDto.getId());
        stockWait.setType(2);//出库
        stockWait.setStatus(0);//待出库
        stockWait.setBusinessType(StockWaitType.PRODUCTION_TASK_OUT.getDetailType());//生产任务出库
        stockWaitService.save(stockWait);
        //创建待出库明细
        List<StockWaitDetails> stockWaitDetailsList = new ArrayList<>();
        for (BomDetail bomDetail : bomDetailList) {
            //计算数量
            BigDecimal multiply = bomDetail.getQuantity().multiply(productionTaskDto.getQuantity());
            //创建待出库明细
            StockWaitDetails stockWaitDetails = new StockWaitDetails();
            stockWaitDetails.setStockWaitId(stockWait.getId());
            stockWaitDetails.setProductId(bomDetail.getProductId());
            stockWaitDetails.setQuantity(multiply);
            stockWaitDetails.setReceiptQuantity(BigDecimal.ZERO);
            stockWaitDetailsList.add(stockWaitDetails);
        }
        stockWaitDetailsService.saveBatch(stockWaitDetailsList);
    }

    @Override
    public void edit(ProductionTaskDto productionTaskDto) {
        this.updateById(productionTaskDto);
    }

    @Override
    public void delete(Long id) {
        this.removeById(id);
    }

    @Override
    public List<ProductionTaskVo> myListByIds(List<Long> ids) {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.in("pt.id", ids);
        return baseMapper.myListByIds(queryWrapper);
    }

    @DSTransactional
    @Override
    public void addByJxst(ProductionTaskDto productionTaskDto) {
        add(productionTaskDto);
        //获取生产计划信息
        ProductionPlan productionPlan = productionPlanService.getById(productionTaskDto.getProductionPlanId());
        if (ObjectUtil.isEmpty(productionPlan)) {
            throw new ServiceException("查询不到该任务的生产计划信息");
        }
        //获取工单信息
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());
        if (ObjectUtil.isEmpty(workOrder)) {
            throw new ServiceException("查询不到该任务的工单信息");
        }
        //判断是否为定制 获取工序信息
        Long productionProcessesId;
        Long nextProductionProcessesId = null;
        if ("1".equals(workOrder.getIsCustomized())) {
            List<WorkOrderProductionProcesses> workOrderProductionProcesses = workOrderProductionProcessesService.list(q -> q
                    .eq(WorkOrderProductionProcesses::getWorkOrderId, workOrder.getId())
                    .orderByAsc(WorkOrderProductionProcesses::getSort));
            if (ObjectUtil.isEmpty(workOrderProductionProcesses)) {
                throw new ServiceException("定制工单 工序列表为空");
            }
            productionProcessesId = workOrderProductionProcesses.get(0).getId();
            //赋值下一工序id
            if(workOrderProductionProcesses.size()>1){
                nextProductionProcessesId =  workOrderProductionProcesses.get(1).getId();
            }
        } else {
            ApplicableProducts applicableProducts = applicableProductsService.getOne(q -> q.eq(ApplicableProducts::getProductId, workOrder.getProductId()));
            if (ObjectUtil.isEmpty(applicableProducts)) {
                throw new ServiceException("未找到适用于该产品的工艺信息");
            }
            Technology technology = technologyService.getById(applicableProducts.getTechnologyId());
            if (ObjectUtil.isEmpty(technology)) {
                throw new ServiceException("工艺信息不存在");
            }
            String processRoute = technology.getProcessRoute();
            if (ObjectUtil.isEmpty(processRoute)) {
                throw new ServiceException("工艺线路为空");
            }
            String[] split = processRoute.split(",");
            productionProcessesId = Long.valueOf(split[0]);
            //赋值下一工序id
            if(split.length>1){
                nextProductionProcessesId =  Long.valueOf(split[1]);
            }
        }
        //创建任务明细
        List<ProductionTaskDetail> productionTaskDetailList = new ArrayList<>();
        List<ProductionTaskDetailRecord> productionTaskDetailRecordList = new ArrayList<>();
        for (int i = 0; i < productionTaskDto.getQuantity().intValue(); i++) {
            ProductionTaskDetail productionTaskDetail = new ProductionTaskDetail();
            productionTaskDetail.setId(IdWorker.getId());
            productionTaskDetail.setProductionTaskId(productionTaskDto.getId());//任务id
            productionTaskDetail.setFinishStatus(0);//默认状态未完工
            productionTaskDetail.setProductId(workOrder.getProductId());//产品id
            productionTaskDetail.setProductionProcessesId(productionProcessesId);//第一个工序id
            productionTaskDetail.setNextProductionProcessesId(nextProductionProcessesId);//第二个工序id
            //生成SN
            productionTaskDetail.setProductSn(String.format("%s-%03d", productionTaskDto.getCode(), i + 1));
            productionTaskDetail.setPersonLiableId(productionTaskDto.getPersonLiableId());//负责人ID
            productionTaskDetailList.add(productionTaskDetail);
            //创建任务明细记录
            ProductionTaskDetailRecord productionTaskDetailRecord = new ProductionTaskDetailRecord();
            productionTaskDetailRecord.setProductionTaskDetailId(productionTaskDetail.getId());
            productionTaskDetailRecord.setProductionProcessesId(productionProcessesId);
            productionTaskDetailRecord.setPersonLiableId(productionTaskDto.getPersonLiableId());
            productionTaskDetailRecordList.add(productionTaskDetailRecord);
        }
        productionTaskDetailService.saveBatch(productionTaskDetailList);
        productionTaskDetailRecordService.saveBatch(productionTaskDetailRecordList);
    }

    @Override
    public ProductionTaskVo detailByJxst(Long id) {
        ProductionTaskVo detail = detail(id);
        //赋值待排程数
        Long productionPlanId = detail.getProductionPlanId();
        ProductionPlan productionPlan = productionPlanService.getById(productionPlanId);
        List<ProductionTask> list1 = list(q -> q.eq(ProductionTask::getProductionPlanId, productionPlan.getId()));
        BigDecimal remainingQuantity = productionPlan.getQuantity().subtract(BigDecimal.valueOf(list1.size()));
        detail.setRemainingQuantity(remainingQuantity);
        detail.setProductionPlanCode(productionPlan.getCode());

        List<ProductionTaskDetail> list = productionTaskDetailService.list(q -> q.eq(ProductionTaskDetail::getProductionTaskId, id));
        List<ProductionTaskDetailVo> productionTaskDetailVos = BeanUtil.copyToList(list, ProductionTaskDetailVo.class);
        //赋值当前工序名称
        WorkOrder workOrder = workOrderService.getById(productionPlan.getWorkOrderId());
        //判断是否是定制工单 获取指定工序
        if ("1".equals(workOrder.getIsCustomized())) {
            //获取定制工序
            Map<Long, String> gxmap = workOrderProductionProcessesService.mapKV(WorkOrderProductionProcesses::getId, WorkOrderProductionProcesses::getName, q -> q.eq(WorkOrderProductionProcesses::getWorkOrderId, workOrder.getId()));
            if (ObjectUtil.isNotEmpty(gxmap)) {
                for (ProductionTaskDetailVo productionTaskDetail : productionTaskDetailVos) {
                    String gxname = gxmap.get(productionTaskDetail.getProductionProcessesId());
                    productionTaskDetail.setProductionProcessesName(gxname);
                }
            }
        } else {
            //获取基本工序
            ApplicableProducts applicableProducts = applicableProductsService.getOne(q -> q.eq(ApplicableProducts::getProductId, workOrder.getProductId()));
            if (ObjectUtil.isNotEmpty(applicableProducts)) {
                Technology technology = technologyService.getById(applicableProducts.getTechnologyId());
                if (ObjectUtil.isNotEmpty(technology)) {
                    String processRoute = technology.getProcessRoute();
                    if (ObjectUtil.isNotEmpty(processRoute)) {
                        String[] split = processRoute.split(",");
                        Map<Long, String> gxmap = productionProcessesService.mapKV(ProductionProcesses::getId, ProductionProcesses::getName, q -> q.in(ProductionProcesses::getId, split));
                        for (ProductionTaskDetailVo productionTaskDetail : productionTaskDetailVos) {
                            String gxname = gxmap.get(productionTaskDetail.getProductionProcessesId());
                            productionTaskDetail.setProductionProcessesName(gxname);
                        }
                    }
                }
            }
        }
        //赋值累计耗时
        for (ProductionTaskDetailVo productionTaskDetail : productionTaskDetailVos) {
            long diff = new Date().getTime() - productionTaskDetail.getCreateTime().getTime();
            DecimalFormat decimalFormat = new DecimalFormat("#0.00");
            String formattedResult = decimalFormat.format(diff / 60.0 / 60.0 / 1000.0);
            productionTaskDetail.setCumulativeTime(formattedResult);

            //判断是否完工
            if(productionTaskDetail.getFinishStatus()==1){
                productionTaskDetail.setProductionProcessesName("已完成");
            }
        }
        detail.setProductionTaskDetailList(productionTaskDetailVos);
        return detail;
    }

}
