package easydo.technology.service.impl;

import easydo.technology.components.JdbcClient;
import easydo.technology.enums.MESEnum;
import easydo.technology.exception.BizException;
import easydo.technology.model.*;
import easydo.technology.service.FlowNoService;
import easydo.technology.service.ProductOrderService;
import easydo.technology.utils.StringUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ProductOrderServiceImpl implements ProductOrderService {

    @Resource
    private JdbcClient jdbcClient;
    @Resource
    private DataSource dataSource;
    @Resource
    private FlowNoService flowNoService;

    @Override
    @SuppressWarnings("unchecked")
    public Map<String, Object> getPage(Map<String, Object> map) throws Exception {
        Connection connection = dataSource.getConnection();
        try {
            // 1) 查询工单分页数据
            Map<String, Object> result = jdbcClient.getJdbcPage(map, ProductOrder.class, connection);
            List<ProductOrder> list = (List<ProductOrder>) result.get("records");
            if (list == null || list.isEmpty()) {
                return result;
            }

            // 1.1) 收集所有工单ID，用于批量查询派工记录
            List<String> orderIds = new ArrayList<>();
            for (ProductOrder model : list) {
                orderIds.add(model.getId());
            }
            
            // 1.2) 批量查询所有工单的派工记录
            Map<String, List<ProductOrderDispatch>> orderDispatchMap = batchQueryDispatchRecords(orderIds, connection);

            for (ProductOrder model : list) {
                // 2) 查询并回填工单的附件
                jdbcClient.getMinioFile(model, connection);

                // 3) 查询并回填关联生产计划
                if (model.getPlanId() != null) {
                    ProductPlan planParam = new ProductPlan();
                    planParam.setId(model.getPlanId());
                    ProductPlan plan = jdbcClient.getJdbcModelById(planParam, connection);
                    model.setProductPlan(plan);
                }

                // 4) 查询并回填工单 BOM 列表
                ProductOrderBom bomParam = new ProductOrderBom();
                bomParam.setOrderId(model.getId());
                List<ProductOrderBom> bomList = jdbcClient.getJdbcList(bomParam, connection);
                if (bomList != null) {
                    for (ProductOrderBom orderBom : bomList) {
                        // 4.1) 工艺路线
                        if (orderBom.getRouteId() != null) {
                            ProcessRoute routeParam = new ProcessRoute();
                            routeParam.setId(orderBom.getRouteId());
                            ProcessRoute route = jdbcClient.getJdbcModelById(routeParam, connection);
                            
                            // 4.1.1) 查询工艺路线的工序明细列表（按 order_num 排序）
                            if (route != null) {
                                Map<String, Object> detailQueryMap = new HashMap<>();
                                detailQueryMap.put("routeId", route.getId());
                                detailQueryMap.put("orderBy", "orderNum_asc");
                                List<ProcessRouteDetail> detailList = jdbcClient.getJdbcList(detailQueryMap, ProcessRouteDetail.class, connection);
                                
                                // 补齐每个工序明细的工序信息
                                if (detailList != null) {
                                    for (ProcessRouteDetail detail : detailList) {
                                        if (detail.getStageId() != null) {
                                            ProcessStage stageParam = new ProcessStage();
                                            stageParam.setId(detail.getStageId());
                                            detail.setStage(jdbcClient.getJdbcModelById(stageParam, connection));
                                        }
                                    }
                                }
                                
                                route.setDetailList(detailList);
                            }
                            
                            orderBom.setProcessRoute(route);
                        }
                        // 4.2) 质检方案
                        if (orderBom.getInspectProgramId() != null) {
                            QualityInspectProgram programParam = new QualityInspectProgram();
                            programParam.setId(orderBom.getInspectProgramId());
                            orderBom.setInspectProgram(jdbcClient.getJdbcModelById(programParam, connection));
                        }
                        // 4.3) 产品 BOM
                        if (orderBom.getBomId() != null) {
                            ProductBom productBomParam = new ProductBom();
                            productBomParam.setId(orderBom.getBomId());
                            ProductBom productBom = jdbcClient.getJdbcModelById(productBomParam, connection);
                            
                            // 4.3.1) 查询 ProductBom 的物料信息
                            if (productBom != null && productBom.getMaterialCode() != null) {
                                ProductMaterial materialParam = new ProductMaterial();
                                materialParam.setCode(productBom.getMaterialCode());
                                productBom.setMaterial(jdbcClient.getJdbcModel(materialParam, connection));
                            }
                            
                            orderBom.setProductBom(productBom);
                        }
                    }
                }
                model.setBomList(bomList);

                // 5) 查询并回填工单设备列表
                ProductOrderDevice deviceParam = new ProductOrderDevice();
                deviceParam.setOrderId(model.getId());
                List<ProductOrderDevice> deviceList = jdbcClient.getJdbcList(deviceParam, connection);
                if (deviceList != null) {
                    for (ProductOrderDevice orderDevice : deviceList) {
                        if (orderDevice.getDeviceId() != null) {
                            Device deviceModel = new Device();
                            deviceModel.setId(orderDevice.getDeviceId());
                            orderDevice.setDevice(jdbcClient.getJdbcModelById(deviceModel, connection));
                        }
                    }
                }
                model.setDeviceList(deviceList);

                // 6) 判断是否可以派工（使用批量查询的结果）
                List<ProductOrderDispatch> dispatchList = orderDispatchMap.get(model.getId());
                boolean canDispatch = checkCanDispatch(model, dispatchList);
                model.setCanDispatch(canDispatch);
            }

            return result;
        } catch (Exception e) {
            throw new BizException(e.getMessage());
        } finally {
            connection.close();
        }
    }

    @Override
    public ProductOrder save(ProductOrder model) throws Exception {
        Connection connection = dataSource.getConnection();
        connection.setAutoCommit(false);
        try {
            // 1) 生成编码（支持手填校验 + 自动生成）
            String code = flowNoService.generateProductOrderCode(model, connection);
            model.setCode(code);

            // 2) 设置初始状态为 pending
            model.setStatus(MESEnum.PRODUCT_ORDER_OF_STATUS_PENDING.getValue());

            // 3) 插入主表（会自动保存附件 fileList）
            jdbcClient.jdbcInsert(model, connection);

            // 4) 插入 BOM 列表
            List<ProductOrderBom> bomList = model.getBomList();
            if (bomList != null) {
                for (ProductOrderBom bom : bomList) {
                    bom.setOrderId(model.getId());
                    
                    // 根据 bomId 查询 product_bom 表获取工艺路线ID
                    if (bom.getBomId() != null) {
                        ProductBom productBomParam = new ProductBom();
                        productBomParam.setId(bom.getBomId());
                        ProductBom productBom = jdbcClient.getJdbcModelById(productBomParam, connection);
                        if (productBom != null && productBom.getRouteId() != null) {
                            bom.setRouteId(productBom.getRouteId());
                            
                            // 根据工艺路线ID查询工艺路线表获取质检方案ID
                            ProcessRoute processRouteParam = new ProcessRoute();
                            processRouteParam.setId(productBom.getRouteId());
                            ProcessRoute processRoute = jdbcClient.getJdbcModelById(processRouteParam, connection);
                            if (processRoute != null && processRoute.getInspectProgramId() != null) {
                                bom.setInspectProgramId(processRoute.getInspectProgramId());
                            }
                        }
                    }
                    
                    jdbcClient.jdbcInsert(bom, connection);
                }
            }

            // 5) 插入设备列表
            List<ProductOrderDevice> deviceList = model.getDeviceList();
            if (deviceList != null) {
                for (ProductOrderDevice device : deviceList) {
                    device.setOrderId(model.getId());
                    jdbcClient.jdbcInsert(device, connection);
                }
            }

            // 6) 若工单关联了生产计划，则将对应生产计划状态更新为 processing
            if (StringUtil.isNotEmpty(model.getPlanId())) {
                ProductPlan productPlan = new ProductPlan();
                productPlan.setId(model.getPlanId());
                productPlan.setStatus(MESEnum.PRODUCT_PLAN_OF_STATUS_PROCESSING.getValue());
                jdbcClient.jdbcUpdateById(productPlan, connection);
            }

            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw new BizException(e.getMessage());
        } finally {
            connection.close();
        }
    }

    @Override
    public ProductOrder update(ProductOrder model) throws Exception {
        Connection connection = dataSource.getConnection();
        connection.setAutoCommit(false);
        try {
            // 1) 更新主表（会自动保存附件 fileList）
            jdbcClient.jdbcUpdateById(model, connection);

            // 2) 删除旧 BOM 列表
            ProductOrderBom bomRemoveParam = new ProductOrderBom();
            bomRemoveParam.setOrderId(model.getId());
            jdbcClient.jdbcRemove(bomRemoveParam, connection);

            // 3) 插入新 BOM 列表
            List<ProductOrderBom> bomList = model.getBomList();
            if (bomList != null) {
                for (ProductOrderBom bom : bomList) {
                    bom.setOrderId(model.getId());
                    
                    // 根据 bomId 查询 product_bom 表获取工艺路线ID
                    if (bom.getBomId() != null) {
                        ProductBom productBomParam = new ProductBom();
                        productBomParam.setId(bom.getBomId());
                        ProductBom productBom = jdbcClient.getJdbcModelById(productBomParam, connection);
                        if (productBom != null && productBom.getRouteId() != null) {
                            bom.setRouteId(productBom.getRouteId());
                            
                            // 根据工艺路线ID查询工艺路线表获取质检方案ID
                            ProcessRoute processRouteParam = new ProcessRoute();
                            processRouteParam.setId(productBom.getRouteId());
                            ProcessRoute processRoute = jdbcClient.getJdbcModelById(processRouteParam, connection);
                            if (processRoute != null && processRoute.getInspectProgramId() != null) {
                                bom.setInspectProgramId(processRoute.getInspectProgramId());
                            }
                        }
                    }
                    
                    jdbcClient.jdbcInsert(bom, connection);
                }
            }

            // 4) 删除旧设备列表
            ProductOrderDevice deviceRemoveParam = new ProductOrderDevice();
            deviceRemoveParam.setOrderId(model.getId());
            jdbcClient.jdbcRemove(deviceRemoveParam, connection);

            // 5) 插入新设备列表
            List<ProductOrderDevice> deviceList = model.getDeviceList();
            if (deviceList != null) {
                for (ProductOrderDevice device : deviceList) {
                    device.setOrderId(model.getId());
                    jdbcClient.jdbcInsert(device, connection);
                }
            }

            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw new BizException(e.getMessage());
        } finally {
            connection.close();
        }
    }

    @Override
    public ProductOrder remove(ProductOrder model) throws Exception {
        Connection connection = dataSource.getConnection();
        connection.setAutoCommit(false);
        try {
            // 1) 删除主表（JdbcClient 会自动删除附件）
            jdbcClient.jdbcRemoveById(model, connection);

            // 2) 删除 BOM 列表
            ProductOrderBom bomRemoveParam = new ProductOrderBom();
            bomRemoveParam.setOrderId(model.getId());
            jdbcClient.jdbcRemove(bomRemoveParam, connection);

            // 3) 删除设备列表
            ProductOrderDevice deviceRemoveParam = new ProductOrderDevice();
            deviceRemoveParam.setOrderId(model.getId());
            jdbcClient.jdbcRemove(deviceRemoveParam, connection);

            connection.commit();
            return model;
        } catch (Exception e) {
            connection.rollback();
            throw new BizException(e.getMessage());
        } finally {
            connection.close();
        }
    }

    /**
     * 批量查询多个工单的派工记录
     * 
     * @param orderIds 工单ID列表
     * @param connection 数据库连接
     * @return Map<工单ID, 派工记录列表>
     */
    private Map<String, List<ProductOrderDispatch>> batchQueryDispatchRecords(List<String> orderIds, Connection connection) throws Exception {
        Map<String, List<ProductOrderDispatch>> resultMap = new HashMap<>();
        
        if (orderIds == null || orderIds.isEmpty()) {
            return resultMap;
        }
        
        // 使用 IN 查询批量获取派工记录
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("orderId_in", orderIds);
        List<ProductOrderDispatch> allDispatches = jdbcClient.getJdbcList(queryMap, ProductOrderDispatch.class, connection);
        
        // 按工单ID分组
        if (allDispatches != null) {
            for (ProductOrderDispatch dispatch : allDispatches) {
                String orderId = dispatch.getOrderId();
                resultMap.computeIfAbsent(orderId, k -> new ArrayList<>()).add(dispatch);
            }
        }
        
        return resultMap;
    }

    /**
     * 判断工单是否可以派工
     * 
     * @param order 工单对象
     * @param dispatchList 该工单的派工记录列表（已批量查询）
     * @return true-可以派工，false-不可以派工
     */
    private boolean checkCanDispatch(ProductOrder order, List<ProductOrderDispatch> dispatchList) {
        // 1. 工单状态必须是待进行或进行中
        String status = order.getStatus();
        if (status == null || 
            (!MESEnum.PRODUCT_ORDER_OF_STATUS_PENDING.getValue().equals(status) && 
             !MESEnum.PRODUCT_ORDER_OF_STATUS_PROCESSING.getValue().equals(status))) {
            return false;
        }

        // 2. 必须有 BOM 列表
        List<ProductOrderBom> bomList = order.getBomList();
        if (bomList == null || bomList.isEmpty()) {
            return false;
        }

        // 3. 每个 BOM 必须关联工艺路线，且工艺路线必须有可报工工序（isReport=true）
        for (ProductOrderBom bom : bomList) {
            // 3.1 检查是否有工艺路线
            if (bom.getRouteId() == null || bom.getRouteId().trim().isEmpty()) {
                return false;
            }

            // 3.2 检查工艺路线是否有工序明细
            ProcessRoute route = bom.getProcessRoute();
            if (route == null) {
                return false;
            }

            List<ProcessRouteDetail> detailList = route.getDetailList();
            if (detailList == null || detailList.isEmpty()) {
                return false;
            }

            // 3.3 至少要有一个可派工工序（isReport=true）
            boolean hasReportStage = false;
            for (ProcessRouteDetail detail : detailList) {
                if (Boolean.TRUE.equals(detail.getIsReport()) && detail.getStageId() != null) {
                    hasReportStage = true;
                    break;
                }
            }
            if (!hasReportStage) {
                return false;
            }
        }

        // 4. 检查是否还有未派完工的工序
        // 统计每个 (bomId, stageId) 组合的已派工数量
        Map<String, Double> dispatchedQuantityMap = new HashMap<>();
        if (dispatchList != null) {
            for (ProductOrderDispatch dispatch : dispatchList) {
                // 使用 bomId（product_bom 的 ID）作为 key
                String key = dispatch.getBomId() + "_" + dispatch.getStageId();
                double currentQty = dispatchedQuantityMap.getOrDefault(key, 0.0);
                // orderNum 是派工数量（计划数量）
                if (dispatch.getOrderNum() != null) {
                    currentQty += dispatch.getOrderNum().doubleValue();
                }
                dispatchedQuantityMap.put(key, currentQty);
            }
        }
        
        // 检查是否存在未派完工的工序
        for (ProductOrderBom bom : bomList) {
            // BOM 的总数量
            Double bomTotalQty = bom.getNumber();
            if (bomTotalQty == null || bomTotalQty <= 0) {
                continue;
            }
            
            ProcessRoute route = bom.getProcessRoute();
            if (route != null && route.getDetailList() != null) {
                for (ProcessRouteDetail detail : route.getDetailList()) {
                    // 仅可报工工序（isReport=true）参与派工判断
                    if (Boolean.TRUE.equals(detail.getIsReport()) && detail.getStageId() != null) {
                        // 使用 bomId（product_bom 的 ID）而不是 product_order_bom 的 id
                        String key = bom.getBomId() + "_" + detail.getStageId();
                        double dispatchedQty = dispatchedQuantityMap.getOrDefault(key, 0.0);
                        
                        // 使用容差比较，避免浮点数精度问题
                        if (dispatchedQty < bomTotalQty - 0.0001) {
                            return true;
                        }
                    }
                }
            }
        }
        
        // 所有工序的数量都已派完，不能再派工
        return false;
    }
}
