package com.aucma.base.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.aucma.base.domain.BaseMaterialInfo;
import com.aucma.base.domain.BaseOrderInfo;
import com.aucma.base.mapper.BaseOrderInfoMapper;
import com.aucma.base.service.IBusinessCodeGeneratorService;
import com.aucma.base.service.IBaseMaterialInfoService;
import com.aucma.base.service.IBaseOrderInfoService;
import com.aucma.common.exception.ServiceException;
import com.aucma.common.utils.DateUtils;
import com.aucma.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 工单信息Service业务层处理
 *
 * @author Yinq
 * @date 2023-09-27
 */
@Service
public class BaseOrderInfoServiceImpl implements IBaseOrderInfoService {
    private static final String DEFAULT_WORK_CENTER_CODE = "7";

    @Autowired
    private BaseOrderInfoMapper baseOrderInfoMapper;

    @Autowired
    private IBaseMaterialInfoService baseMaterialInfoService;

    @Autowired
    private IBusinessCodeGeneratorService businessCodeGeneratorService;

    /**
     * 查询工单信息
     *
     * @param objId 工单信息主键
     * @return 工单信息
     */
    @Override
    public BaseOrderInfo selectBaseOrderInfoByObjId(Long objId) {
        return baseOrderInfoMapper.selectBaseOrderInfoByObjId(objId);
    }

    /**
     * 查询工单信息列表
     *
     * @param baseOrderInfo 工单信息
     * @return 工单信息
     */
    @Override
    public List<BaseOrderInfo> selectBaseOrderInfoList(BaseOrderInfo baseOrderInfo) {
        return baseOrderInfoMapper.selectBaseOrderInfoList(baseOrderInfo);
    }

    /**
     * 查询ALL工单信息列表
     *
     * @param baseOrderInfo 工单信息
     * @return 工单信息
     */
    @Override
    public List<BaseOrderInfo> selectAllOrderInfoList(BaseOrderInfo baseOrderInfo) {
        return baseOrderInfoMapper.selectAllOrderInfoList(baseOrderInfo);
    }

    /**
     * PDA按物料关键字查询工单列表
     */
    @Override
    public List<BaseOrderInfo> selectPdaOrderListByMaterialKeyword(String materialKeyword) {
        // 第一步：先在物料主数据中做模糊匹配，保证PDA搜索结果受主数据启停与编码口径约束
        List<BaseMaterialInfo> materials = baseMaterialInfoService.selectPdaMaterialListByKeyword(materialKeyword);
        if (materials == null || materials.isEmpty()) {
            return new ArrayList<>();
        }
        Set<String> materialCodes = new LinkedHashSet<>();
        for (BaseMaterialInfo material : materials) {
            // 用LinkedHashSet去重并保序，避免同物料重复命中导致订单列表重复
            if (material.getMaterialCode() != null && !material.getMaterialCode().trim().isEmpty()) {
                materialCodes.add(material.getMaterialCode().trim());
            }
        }
        if (materialCodes.isEmpty()) {
            return new ArrayList<>();
        }
        // 第二步：按物料编码集合回查订单，减少在订单表直接做模糊搜索带来的性能与误匹配风险
        return baseOrderInfoMapper.selectPdaOrderListByMaterialCodes(new ArrayList<>(materialCodes));
    }

    /**
     * 新增工单信息
     *
     * @param baseOrderInfo 工单信息
     * @return 结果
     */
    @Override
    public int insertBaseOrderInfo(BaseOrderInfo baseOrderInfo) {
        fillInsertDefaults(baseOrderInfo);
        syncMaterialMasterFields(baseOrderInfo);
        baseOrderInfo.setCreatedTime(DateUtils.getNowDate());
        return baseOrderInfoMapper.insertBaseOrderInfo(baseOrderInfo);
    }

    /**
     * 修改工单信息
     *
     * @param baseOrderInfo 工单信息
     * @return 结果
     */
    @Override
    public int updateBaseOrderInfo(BaseOrderInfo baseOrderInfo) {
        preserveOrderCodeOnUpdate(baseOrderInfo);
        syncMaterialMasterFields(baseOrderInfo);
        baseOrderInfo.setUpdatedTime(DateUtils.getNowDate());
        return baseOrderInfoMapper.updateBaseOrderInfo(baseOrderInfo);
    }

    /**
     * 批量删除工单信息
     *
     * @param objIds 需要删除的工单信息主键
     * @return 结果
     */
    @Override
    public int deleteBaseOrderInfoByObjIds(Long[] objIds) {
        return baseOrderInfoMapper.deleteBaseOrderInfoByObjIds(objIds);
    }

    /**
     * 删除工单信息信息
     *
     * @param objId 工单信息主键
     * @return 结果
     */
    @Override
    public int deleteBaseOrderInfoByObjId(Long objId) {
        return baseOrderInfoMapper.deleteBaseOrderInfoByObjId(objId);
    }

    /**
     * 根据工单编号查询工单
     */
    @Override
    public BaseOrderInfo selectBaseOrderInfoByOrderCode(String orderCode) {
        BaseOrderInfo query = new BaseOrderInfo();
        query.setOrderCode(orderCode);
        List<BaseOrderInfo> list = baseOrderInfoMapper.selectAllOrderInfoList(query);
        return list != null && !list.isEmpty() ? list.get(0) : null;
    }

    /**
     * 开始生产
     */
    @Override
    public int startProduction(String orderCode, String operator) {
        BaseOrderInfo order = selectBaseOrderInfoByOrderCode(orderCode);
        if (order == null) {
            return 0;
        }
        order.setExecutionStatus("RUNNING");
        order.setStartTime(new Date());
        order.setExecutionOperator(operator);
        order.setUpdatedTime(DateUtils.getNowDate());
        return baseOrderInfoMapper.updateBaseOrderInfo(order);
    }

    /**
     * 完工提报
     */
    @Override
    public int completeProduction(String orderCode, Long completeQty, Long defectQty) {
        BaseOrderInfo order = selectBaseOrderInfoByOrderCode(orderCode);
        if (order == null) {
            return 0;
        }
        order.setExecutionStatus("COMPLETED");
        order.setFinishTime(new Date());
        order.setActualCompleteQty(completeQty);
        order.setActualDefectQty(defectQty);
        // 同步列表展示字段
        order.setCompleteAmount(completeQty);
        order.setCompleteDate(new Date());
        order.setUpdatedTime(DateUtils.getNowDate());
        return baseOrderInfoMapper.updateBaseOrderInfo(order);
    }

    /**
     * 更新完工数量
     */
    @Override
    public int updateQuantity(String orderCode, Long completeQty, Long defectQty) {
        BaseOrderInfo order = selectBaseOrderInfoByOrderCode(orderCode);
        if (order == null) {
            return 0;
        }
        order.setActualCompleteQty(completeQty);
        order.setActualDefectQty(defectQty);
        // 同步列表展示字段
        order.setCompleteAmount(completeQty);
        order.setUpdatedTime(DateUtils.getNowDate());
        return baseOrderInfoMapper.updateBaseOrderInfo(order);
    }

    /**
     * 获取正在执行的工单列表
     */
    @Override
    public List<BaseOrderInfo> getRunningOrders() {
        BaseOrderInfo query = new BaseOrderInfo();
        query.setExecutionStatus("RUNNING");
        return baseOrderInfoMapper.selectAllOrderInfoList(query);
    }

    /**
     * 获取指定设备正在执行的工单
     */
    @Override
    public BaseOrderInfo getRunningOrderByDevice(String deviceCode) {
        BaseOrderInfo query = new BaseOrderInfo();
        query.setDeviceCode(deviceCode);
        query.setExecutionStatus("RUNNING");
        List<BaseOrderInfo> list = baseOrderInfoMapper.selectBaseOrderInfoList(query);
        return list != null && !list.isEmpty() ? list.get(0) : null;
    }

    /**
     * 批量开始生产
     *
     * @param objIds 工单ID集合
     * @param operator 操作员
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchStartProduction(Long[] objIds, String operator) {
        if (objIds == null || objIds.length == 0) {
            return 0;
        }
        if (operator == null || operator.isEmpty()) {
            throw new RuntimeException("操作员不能为空");
        }
        Date now = DateUtils.getNowDate();
        return baseOrderInfoMapper.batchStartProduction(objIds, operator, now);
    }

    /**
     * 批量更新完工数量
     *
     * @param objIds 工单ID集合
     * @param completeQty 完工数量
     * @param defectQty 不良数量
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchUpdateQuantity(Long[] objIds, Long completeQty, Long defectQty) {
        if (objIds == null || objIds.length == 0) {
            return 0;
        }
        if (completeQty == null) {
            completeQty = 0L;
        }
        if (defectQty == null) {
            defectQty = 0L;
        }
        Date now = DateUtils.getNowDate();
        return baseOrderInfoMapper.batchUpdateQuantity(objIds, completeQty, defectQty, now);
    }

    /**
     * 批量完工提报
     *
     * @param objIds 工单ID集合
     * @param completeQty 完工数量
     * @param defectQty 不良数量
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchCompleteProduction(Long[] objIds, Long completeQty, Long defectQty) {
        if (objIds == null || objIds.length == 0) {
            return 0;
        }
        if (completeQty == null) {
            completeQty = 0L;
        }
        if (defectQty == null) {
            defectQty = 0L;
        }
        Date now = DateUtils.getNowDate();
        return baseOrderInfoMapper.batchCompleteProduction(objIds, completeQty, defectQty, now);
    }

    /**
     * PDA维护工单状态与数量
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updatePdaOrderExecution(BaseOrderInfo baseOrderInfo) {
        if (baseOrderInfo == null) {
            return 0;
        }
        BaseOrderInfo order = null;
        // 优先按主键定位，避免工单编号存在历史重复或外部系统口径不一致时误更新
        if (baseOrderInfo.getObjId() != null) {
            order = baseOrderInfoMapper.selectBaseOrderInfoByObjId(baseOrderInfo.getObjId());
        }
        // 仅在没有主键时再退化为按工单编号查找，兼容PDA轻量传参
        if (order == null && baseOrderInfo.getOrderCode() != null && !baseOrderInfo.getOrderCode().trim().isEmpty()) {
            order = selectBaseOrderInfoByOrderCode(baseOrderInfo.getOrderCode().trim());
        }
        if (order == null) {
            return 0;
        }

        Date now = DateUtils.getNowDate();
        // Why：该标识用于区分SAP/计划系统同步数据与PDA人工干预数据，方便后续追溯
        order.setManualUpdateFlag("1");
        order.setUpdatedTime(now);

        // 执行状态允许人工修正，但仍受控制器的枚举校验约束
        if (baseOrderInfo.getExecutionStatus() != null && !baseOrderInfo.getExecutionStatus().trim().isEmpty()) {
            order.setExecutionStatus(baseOrderInfo.getExecutionStatus().trim());
        }
        if (baseOrderInfo.getActualCompleteQty() != null) {
            // 列表页展示兼容completeAmount，因此这里同步两套字段，避免前后端显示不一致
            order.setActualCompleteQty(baseOrderInfo.getActualCompleteQty());
            order.setCompleteAmount(baseOrderInfo.getActualCompleteQty());
        }
        if (baseOrderInfo.getActualDefectQty() != null) {
            order.setActualDefectQty(baseOrderInfo.getActualDefectQty());
        }

        // 人工将工单切到运行中时，如果系统尚未记录开工时间，则补记当前时间
        if ("RUNNING".equals(order.getExecutionStatus()) && order.getStartTime() == null) {
            order.setStartTime(now);
        }
        if ("COMPLETED".equals(order.getExecutionStatus())) {
            // Why：PDA显式将工单维护为已完成时，需要同步完工时间与完成日期，保证执行页和报表口径一致
            order.setFinishTime(now);
            order.setCompleteDate(now);
        }

        return baseOrderInfoMapper.updateBaseOrderInfo(order);
    }

    private void syncMaterialMasterFields(BaseOrderInfo baseOrderInfo)
    {
        if (baseOrderInfo == null || StringUtils.isBlank(baseOrderInfo.getMaterialCode())) {
            throw new ServiceException("物料编码不能为空，请先选择物料");
        }
        BaseMaterialInfo query = new BaseMaterialInfo();
        query.setMaterialCode(baseOrderInfo.getMaterialCode().trim());
        List<BaseMaterialInfo> materialInfoList = baseMaterialInfoService.selectBaseMaterialInfoList(query);
        if (materialInfoList == null || materialInfoList.isEmpty()) {
            throw new ServiceException("物料编码不存在，请重新选择物料");
        }
        BaseMaterialInfo materialInfo = materialInfoList.get(0);
        baseOrderInfo.setMaterialCode(materialInfo.getMaterialCode());
        // 为什么要以后端回填为准：订单的物料名称和物料组属于主数据快照，不能信任前端传参，避免绕过选择弹窗写入脏数据。
        baseOrderInfo.setMaterialName(materialInfo.getMaterialName());
        baseOrderInfo.setMatkl(materialInfo.getMaterialMatkl());
    }

    private void fillInsertDefaults(BaseOrderInfo baseOrderInfo) {
        if (baseOrderInfo == null) {
            throw new ServiceException("工单信息不能为空");
        }
        // 为什么新增时一律由后端生成编号：只有服务端统一串行分配，才能在并发新增时避免同一编号被重复使用。
        baseOrderInfo.setOrderCode(businessCodeGeneratorService.generateSapPlanCode(DateUtils.getNowDate()));
        if (StringUtils.isBlank(baseOrderInfo.getWorkCenterCode())) {
            // 为什么默认给工作中心 7：满足当前业务默认值要求，同时保留前端可改动能力，未显式选择时也能稳定落库。
            baseOrderInfo.setWorkCenterCode(DEFAULT_WORK_CENTER_CODE);
        }
    }

    private void preserveOrderCodeOnUpdate(BaseOrderInfo baseOrderInfo) {
        if (baseOrderInfo == null || baseOrderInfo.getObjId() == null) {
            return;
        }
        if (StringUtils.isNotBlank(baseOrderInfo.getOrderCode())) {
            baseOrderInfo.setOrderCode(baseOrderInfo.getOrderCode().trim());
            return;
        }
        BaseOrderInfo existedOrder = baseOrderInfoMapper.selectBaseOrderInfoByObjId(baseOrderInfo.getObjId());
        if (existedOrder == null) {
            throw new ServiceException("工单不存在，无法更新");
        }
        baseOrderInfo.setOrderCode(existedOrder.getOrderCode());
    }
}
