package cn.iocoder.yudao.module.pms.job.sap;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.pms.dal.mysql.iotsapstock.IotSapStockMapper;
import cn.iocoder.yudao.module.pms.sap.SapConnector;
import cn.iocoder.yudao.module.pms.sap.service.IotSapService;
import cn.iocoder.yudao.module.pms.sap.vo.IotSapStockVO;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.saporg.SapOrgApi;
import cn.iocoder.yudao.module.system.api.saporg.dto.SapOrgRespDTO;
import com.sap.conn.jco.JCoFunction;
import com.sap.conn.jco.JCoParameterList;
import com.sap.conn.jco.JCoTable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;

/**
 * 同步 SAP 库存 定时任务
 */
@Component
@Slf4j
public class SyncSapStockJob implements JobHandler {
    @Autowired
    private SapConnector sapConnector;
    @Autowired
    private SapOrgApi sapOrgApi;

    @Resource(name = PMS_THREAD_POOL_TASK_EXECUTOR)
    private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
    @Autowired
    private IotSapService iotSapService;
    @Autowired
    private IotSapStockMapper iotSapStockMapper;
    @Autowired
    private DeptApi deptApi;

    @Override
    @TenantIgnore
    public String execute(String param) throws Exception {
        // 查询所有工厂 根据工厂 多线程处理 SAP 库存
        List<String> factoryCodes = factoryCodes();
        if (CollUtil.isEmpty(factoryCodes)) {
            return "No SAP Factory";
        }
        log.error("共找到 {} 个工厂需要同步: {}", factoryCodes.size(), factoryCodes);

        // 提前获取并缓存基础数据，避免每个线程重复查询
        SyncSapStockContext syncContext = preloadSyncContext();
        if (!syncContext.isValid()) {
            return "基础数据加载失败，无法继续同步";
        }

        long startTime = System.currentTimeMillis();

        // 使用单线程循环处理每个工厂（移除了多线程）
        List<FactorySyncResult> results = new ArrayList<>();
        for (String factory : factoryCodes) {
            try {
                FactorySyncResult result = syncFactoryStockData(factory, syncContext);
                results.add(result);
                log.info("工厂 {} 数据处理完成", factory);
            } catch (Exception e) {
                log.error("工厂 {} 处理过程中发生异常", factory, e);
                results.add(FactorySyncResult.failure(factory, e));
            }
        }

        // 汇总所有工厂的数据
        List<IotSapStockVO> allStockData = new ArrayList<>();
        List<String> failedFactories = new ArrayList<>();
        List<String> successFactories = new ArrayList<>();

        for (FactorySyncResult result : results) {
            if (result.success) {
                if (CollUtil.isNotEmpty(result.stockData)) {
                    allStockData.addAll(result.stockData);
                }
                successFactories.add(result.factoryCode);
                log.error("工厂 {} SAP数据获取成功，获取 {} 条记录", result.factoryCode,
                        CollUtil.size(result.stockData));
            } else {
                failedFactories.add(result.factoryCode);
                log.error("工厂 {} SAP数据获取失败", result.factoryCode, result.error);
            }
        }

        // 统一处理所有库存数据
        if (CollUtil.isNotEmpty(allStockData)) {
            try {
                log.error("开始统一处理所有工厂的库存数据，总计 {} 条记录", allStockData.size());
                iotSapService.processSapStockBatch(allStockData, syncContext);
                log.error("库存数据处理完成");
            } catch (Exception e) {
                log.error("统一处理库存数据时发生错误", e);
                // 如果数据处理失败，认为所有工厂都失败
                failedFactories.addAll(successFactories);
                successFactories.clear();
            }
        }

        long endTime = System.currentTimeMillis();
        log.error("所有工厂同步完成，总耗时: {}ms", (endTime - startTime));

        // 汇总执行结果
        String result = buildResultMessage(factoryCodes.size(), successFactories.size(), failedFactories);
        log.error("SAP库存同步任务完成: {}", result);

        return result;
    }

    /**
     * 同步单个工厂的库存数据（仅获取数据，不处理）
     */
    private FactorySyncResult syncFactoryStockData(String factory, SyncSapStockContext context) {
        JCoFunction function = null;
        try {
            // 每个线程使用独立的JCoFunction实例
            function = context.destination.getRepository().getFunction("ZPMS_002");
            if (function == null) {
                throw new RuntimeException("未找到SAP函数 ZPMS_002");
            }

            // 设置输入参数
            JCoParameterList input = function.getImportParameterList();
            input.setValue("IV_MATNR", "");    // 物料编号
            input.setValue("IV_WERKS", factory);    // 工厂
            input.setValue("IV_LGORT", "");    // 库存地点

            // 执行 RFC 调用
            long startTime = System.currentTimeMillis();
            function.execute(context.destination);
            long endTime = System.currentTimeMillis();

            log.error("工厂 {} SAP调用耗时: {}ms", factory, (endTime - startTime));

            // 处理返回数据
            JCoTable etStockTable = function.getTableParameterList().getTable("ET_STOCK");
            if (etStockTable == null) {
                log.error("工厂 {} 未返回ET_STOCK表数据", factory);
                return FactorySyncResult.success(factory, Collections.emptyList());
            }

            int rowCount = etStockTable.getNumRows();
            log.error("工厂 {} 获取到 {} 条库存数据", factory, rowCount);

            List<IotSapStockVO> sapStocks = Collections.emptyList();
            if (rowCount > 0) {
                sapStocks = parseSapStockData(etStockTable, factory);
                log.error("工厂 {} 解析出 {} 条库存记录", factory, sapStocks.size());
            }

            return FactorySyncResult.success(factory, sapStocks);

        } catch (Exception e) {
            log.error("工厂 {} SAP数据获取失败", factory, e);
            return FactorySyncResult.failure(factory, e);
        } finally {
            // 清理JCo资源
            if (function != null) {
                try {
                    // JCoFunction没有close方法，但可以显式清理
                    function = null;
                } catch (Exception e) {
                    log.error("清理JCoFunction资源时发生警告", e);
                }
            }
        }
    }

    /**
     * 解析SAP库存数据
     */
    private List<IotSapStockVO> parseSapStockData(JCoTable etStockTable, String factory) {
        List<IotSapStockVO> sapStocks = new ArrayList<>();

        for (int i = 0; i < etStockTable.getNumRows(); i++) {
            etStockTable.setRow(i);
            try {
                IotSapStockVO sapStock = new IotSapStockVO();
                sapStock.setWERKS(etStockTable.getString("WERKS"));
                sapStock.setMATNR(etStockTable.getString("MATNR"));
                sapStock.setMAKTX(etStockTable.getString("MAKTX"));
                sapStock.setLABST(etStockTable.getBigDecimal("LABST"));
                sapStock.setLGORT(etStockTable.getString("LGORT"));
                sapStock.setCHARG(etStockTable.getString("CHARG"));
                sapStock.setSOBKZ(etStockTable.getString("SOBKZ"));
                // sapStock.setPSPNR(etStockTable.getString("PSPNR"));
                // sapStock.setPOSID(etStockTable.getString("POSID"));
                sapStock.setMEINS(etStockTable.getString("MEINS"));
                sapStock.setINSME(etStockTable.getString("INSME"));
                sapStock.setSPEME(etStockTable.getString("SPEME"));
                sapStock.setJIAGE(etStockTable.getBigDecimal("JIAGE"));

                sapStocks.add(sapStock);
            } catch (Exception e) {
                log.error("解析工厂 {} 第 {} 行库存数据时发生错误", factory, i, e);
            }
        }

        return sapStocks;
    }

    /**
     * 构建结果消息
     */
    private String buildResultMessage(int total, int success, List<String> failedFactories) {
        StringBuilder result = new StringBuilder();
        result.append("SAP库存同步完成。总计: ").append(total)
                .append(", 成功: ").append(success)
                .append(", 失败: ").append(total - success);

        if (CollUtil.isNotEmpty(failedFactories)) {
            result.append("。失败工厂: ").append(failedFactories);
        }

        return result.toString();
    }

    /**
     * 查询所有SAP工厂
     */
    private List<String> factoryCodes(){
        List<SapOrgRespDTO> sapOrgs = sapOrgApi.getSapOrgByType(1);
        if (CollUtil.isEmpty(sapOrgs)) {
            return CollectionUtil.newArrayList();
        }
        List<String> factoryCodes = sapOrgs.stream()
                .map(SapOrgRespDTO::getFactoryCode)
                .collect(Collectors.toList());
        return CollUtil.isEmpty(factoryCodes) ? CollUtil.empty(String.class) : factoryCodes;
    }

    /**
     * 预加载同步上下文数据
     */
    private SyncSapStockContext preloadSyncContext() {
        SyncSapStockContext context = new SyncSapStockContext();
        try {

            // 提前获取SAP连接
            context.destination = sapConnector.getDestination();
            context.destination.ping(); // 测试连接

            context.existStocks = iotSapStockMapper.allSapStocks();
            context.depts = deptApi.ignoredTenantDepts();
            context.storageLocations = sapOrgApi.getSapOrgByType(3);
            context.factories = sapOrgApi.getSapOrgByType(1);

            // 构建映射关系
            context.buildMappings();

            log.error("同步上下文预加载完成: 工厂{}个, 库存地点{}个, 部门{}个, 现有库存{}条",
                    CollUtil.size(context.factories),
                    CollUtil.size(context.storageLocations),
                    CollUtil.size(context.depts),
                    CollUtil.size(context.existStocks));

            System.out.println(String.format("工厂=%s, 库存地点=%s, 部门=%s, 现有库存=%s",
                    CollUtil.size(context.factories), CollUtil.size(context.storageLocations), CollUtil.size(context.depts), CollUtil.size(context.existStocks)));

            return context;
        } catch (Exception e) {
            log.error("预加载同步上下文失败", e);
            return context.invalid();
        }
    }

    // 内部类用于封装工厂同步结果
    private static class FactorySyncResult {
        String factoryCode;
        List<IotSapStockVO> stockData;
        Exception error;
        boolean success;

        FactorySyncResult(String factoryCode) {
            this.factoryCode = factoryCode;
            this.success = false;
        }

        static FactorySyncResult success(String factoryCode, List<IotSapStockVO> stockData) {
            FactorySyncResult result = new FactorySyncResult(factoryCode);
            result.stockData = stockData;
            result.success = true;
            return result;
        }

        static FactorySyncResult failure(String factoryCode, Exception error) {
            FactorySyncResult result = new FactorySyncResult(factoryCode);
            result.error = error;
            return result;
        }
    }
}
