package com.fjhx.mes.service.work.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.toolkit.CollectionUtils;
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.bom.po.BomDetail;
import com.fjhx.mes.entity.bom.po.BomInfo;
import com.fjhx.mes.entity.production.po.ProductionPlan;
import com.fjhx.mes.entity.production.po.ProductionTask;
import com.fjhx.mes.entity.production.po.ProductionTaskDetail;
import com.fjhx.mes.entity.work.dto.WorkOrderDto;
import com.fjhx.mes.entity.work.dto.WorkOrderSelectDto;
import com.fjhx.mes.entity.work.po.WorkOrder;
import com.fjhx.mes.entity.work.vo.WorkOrderVo;
import com.fjhx.mes.mapper.work.WorkOrderMapper;
import com.fjhx.mes.service.bom.BomDetailService;
import com.fjhx.mes.service.bom.BomInfoService;
import com.fjhx.mes.service.production.ProductionPlanService;
import com.fjhx.mes.service.production.ProductionTaskDetailService;
import com.fjhx.mes.service.production.ProductionTaskService;
import com.fjhx.mes.service.work.WorkOrderService;
import com.fjhx.mes.utils.code.CodeEnum;
import com.fjhx.sale.entity.contract.po.ContractProduct;
import com.fjhx.sale.service.contract.ContractProductService;
import com.fjhx.wms.entity.stock.po.Stock;
import com.fjhx.wms.entity.stock.po.StockFrozen;
import com.fjhx.wms.service.stock.StockFrozenService;
import com.fjhx.wms.service.stock.StockService;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * <p>
 * 工单 服务实现类
 * </p>
 *
 * @author
 * @since 2023-03-29
 */
@Service
public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder> implements WorkOrderService {

    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private ProductionPlanService productionPlanService;

    @Autowired
    private ContractProductService contractProductService;
    @Autowired
    private BomInfoService bomInfoService;
    @Autowired
    private BomDetailService bomDetailService;
    @Autowired
    private StockService stockService;
    @Autowired
    private StockFrozenService stockFrozenService;
    @Autowired
    private ProductionTaskService productionTaskService;
    @Autowired
    private ProductionTaskDetailService productionTaskDetailService;

    @Override
    public Page<WorkOrderVo> getPage(WorkOrderSelectDto dto) {
        IWrapper<WorkOrder> wrapper = getWrapper();
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            wrapper.and(q -> q.like("wo", WorkOrder::getCode, dto.getKeyword())
                    .or()
                    .like("wo", WorkOrder::getQuantity, dto.getKeyword()));
        }
        wrapper.eq("wo", WorkOrder::getSource, dto.getSource());
        wrapper.orderByDesc("wo", WorkOrder::getId);

        //权限过滤：生产工单-子公司看自己的,总公司看全部
        Long companyId = SecurityUtils.getCompanyId();
        if (!Objects.equals(companyId, 100L)) {
            wrapper.eq("wo", WorkOrder::getCompanyId, companyId);
        } else {
            wrapper.eq("wo", WorkOrder::getCompanyId, dto.getCompanyId());
        }

        Page<WorkOrderVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<WorkOrderVo> records = page.getRecords();
        //赋值产品名
        List<Long> productIds = records.stream().map(WorkOrder::getProductId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(productIds)) {
            //赋值产品名称
            productInfoService.attributeAssign(records, WorkOrderVo::getProductId, (item, productInfo) -> {
                item.setProductName(productInfo.getName());
            });
        }
        //赋值待排程数量
        for (WorkOrderVo workOrder : records) {
            workOrder.setRemainingQuantity(workOrder.getQuantity());
        }
        List<Long> workOrderIds = records.stream().map(WorkOrder::getId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(workOrderIds)) {
            List<ProductionPlan> productionPlanList = productionPlanService.list(q -> q.in(ProductionPlan::getWorkOrderId, workOrderIds));
            if (ObjectUtil.isNotEmpty(productionPlanList)) {
                //根据工单id分组
                Map<Long, List<ProductionPlan>> productionPlanMap = productionPlanList.stream().collect(Collectors.groupingBy(ProductionPlan::getWorkOrderId));
                for (WorkOrderVo workOrder : records) {
                    List<ProductionPlan> productionPlanList1 = productionPlanMap.get(workOrder.getId());
                    BigDecimal count = BigDecimal.ZERO;
                    if (ObjectUtil.isNotEmpty(productionPlanList1)) {
                        count = productionPlanList1.stream().map(ProductionPlan::getQuantity)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);
                    }
                    workOrder.setRemainingQuantity(workOrder.getQuantity().subtract(count));
                }
            }
        }
        return page;
    }

    @Override
    public WorkOrderVo detail(Long id) {
        WorkOrder WorkOrder = this.getById(id);
        WorkOrderVo result = BeanUtil.toBean(WorkOrder, WorkOrderVo.class);
        List<ProductionPlan> list = productionPlanService.list(q -> q.eq(ProductionPlan::getWorkOrderId, id));
        result.setProductionPlans(list);
        ProductInfo productInfo = productInfoService.getById(result.getProductId());
        if (ObjectUtil.isNotEmpty(productInfo)) {
            result.setProductName(productInfo.getName());
        }
        return result;
    }

    @DSTransactional
    @Override
    public void add(WorkOrderDto workOrderDto) {
        //生成工单编号,以及设置默认状态
        workOrderDto.setCode(CodeEnum.WORK_ORDER.getCode());
        workOrderDto.setStatus(0);
        this.save(workOrderDto);
        //获取产品信息
        ProductInfo productInfo = productInfoService.getById(workOrderDto.getProductId());
        if (ObjectUtil.isEmpty(productInfo)) {
            throw new ServiceException("查询不到产品信息 产品id->" + workOrderDto.getProductId());
        }
        //搜索BOM明细并到冻结库存
        BomInfo bomInfo = bomInfoService.getOne(q -> q.eq(BomInfo::getProductId, workOrderDto.getProductId()).eq(BomInfo::getCurrentVersion,1));
        if (ObjectUtil.isEmpty(bomInfo)) {
            throw new ServiceException("查询不到产品的BOM信息 产品名称->" + productInfo.getName());
        }
        List<BomDetail> bomDetailList = bomDetailService.list(q -> q.eq(BomDetail::getBomInfoId, bomInfo.getId()));
        if (ObjectUtil.isEmpty(bomDetailList)) {
            throw new ServiceException("查询不到产品BOM明细 产品名称->" + productInfo.getName());
        }
        List<Long> productIds = bomDetailList.stream().map(BomDetail::getProductId).collect(Collectors.toList());
        Map<Long, List<Stock>> productMap = stockService.mapKGroup(Stock::getProductId, q -> q.in(Stock::getProductId, productIds));
        List<StockFrozen> stockFrozenList = new ArrayList<>();
        for (BomDetail bomDetail : bomDetailList) {
            Long productId = bomDetail.getProductId();
            //计算总数量 需要的物料数量*工单数量
            BigDecimal multiply = bomDetail.getQuantity().multiply(workOrderDto.getQuantity());
            //添加冻结库存
            List<Stock> stocks = productMap.get(productId);
            if (ObjectUtil.isEmpty(stocks)) {
                throw new ServiceException("物料库存不存在");
            }
            //计算库存是否充足（可用库存 - 冻结库存 - 所需的数量）是否大等于0
            BigDecimal quantity = stocks.stream().map(Stock::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
            Map<Long, StockFrozen> stockFrozenMap = stockFrozenService.mapKEntity(StockFrozen::getProductId, q -> q.in(StockFrozen::getProductId, productIds));
            StockFrozen stockFrozen = stockFrozenMap.get(bomDetail.getProductId());
            if (ObjectUtil.isEmpty(stockFrozen)) {
                stockFrozen = new StockFrozen();
                stockFrozen.setProductId(bomDetail.getProductId());
                stockFrozen.setFrozenQuantity(BigDecimal.ZERO);
            }
            BigDecimal subtract = quantity.subtract(stockFrozen.getFrozenQuantity()).subtract(multiply);
            if (subtract.compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("物料库存不足");
            }
            //存在库存
            BigDecimal add = stockFrozen.getFrozenQuantity().add(multiply);
            stockFrozen.setFrozenQuantity(add);

            stockFrozenList.add(stockFrozen);
        }
        stockFrozenService.saveOrUpdateBatch(stockFrozenList);
    }

    /**
     * 批量新增
     *
     * @param workOrder
     */
    @Override
    @DSTransactional
    public void addBatch(List<WorkOrder> workOrder) {
        if (CollectionUtils.isEmpty(workOrder)) {
            throw new ServiceException("提交不能为空");
        }
        List<ContractProduct> upContractProduct = new ArrayList<>();
        for (WorkOrder w : workOrder) {
            //生成工单编号,以及设置默认状态
            w.setCode(CodeEnum.WORK_ORDER.getCode());
            w.setStatus(0);
            if (ObjectUtil.isNotEmpty(w.getSourceId()) && "1".equals(w.getSource())) {//外销合同生产数据
                ContractProduct contractProduct = contractProductService.getById(w.getSourceId());
                if (ObjectUtil.isEmpty(contractProduct)) {
                    throw new ServiceException("该合同产品不存在,请检查");
                }
                BigDecimal expendQuantity = contractProduct.getExpendQuantity().subtract(w.getQuantity());
                if (expendQuantity.compareTo(BigDecimal.ZERO) < 0) {
                    //外销合同-交接单转生产 如果转生产数量大于大于合同数量 将待处理数量改为0
                    expendQuantity = BigDecimal.ZERO;
                }
                contractProduct.setExpendQuantity(expendQuantity);
                upContractProduct.add(contractProduct);
            }
        }
        this.saveBatch(workOrder);
        if (CollectionUtils.isNotEmpty(upContractProduct)) {//扣减销售合同数量
            contractProductService.updateBatchById(upContractProduct);
        }
    }

    @Override
    public void edit(WorkOrderDto workOrderDto) {
        this.updateById(workOrderDto);
    }

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

    @Override
    public Page<WorkOrderVo> getPageByJxst(WorkOrderSelectDto dto) {
        Page<WorkOrderVo> page = getPage(dto);
        List<WorkOrderVo> records = page.getRecords();
        for (WorkOrderVo workOrderVo : records) {
            //赋值已计划数量
            workOrderVo.setArrangedQuantity(workOrderVo.getQuantity().subtract(workOrderVo.getRemainingQuantity()));
            //赋值完成率
            long count =0;
            //获取工单下的所有计划
            List<Long> productionPlanIds = productionPlanService.listObject(ProductionPlan::getId,
                    q -> q.eq(ProductionPlan::getWorkOrderId, workOrderVo.getId()));
            if (ObjectUtil.isNotEmpty(productionPlanIds)) {
                //获取计划下的所有任务
                List<Long> productionTaskIds = productionTaskService.listObject(ProductionTask::getId,
                        q -> q.in(ProductionTask::getId, productionPlanIds));
                if (ObjectUtil.isNotEmpty(productionTaskIds)) {
                    count = productionTaskDetailService.count(q ->
                            q.in(ProductionTaskDetail::getProductionTaskId, productionTaskIds)
                                    .eq(ProductionTaskDetail::getFinishStatus, 1));
                }
            }
            BigDecimal divide = BigDecimal.valueOf(count).divide(workOrderVo.getQuantity(), 2, RoundingMode.HALF_UP);
            workOrderVo.setCompletionRate(divide);
        }
        return page;
    }

}
