package com.scpyun.platform.jilinsscgsdp.utils;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.scpyun.base.core.utils.StringUtils;
import com.scpyun.base.core.utils.UUIDUtil;
import com.scpyun.base.db.service.CommonService;
import com.scpyun.platform.jilinsscgsdp.bean.entity.InboundImp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

public class InboundFileListener extends AnalysisEventListener<InboundImp> {
    private static final Logger log = LoggerFactory.getLogger(InboundFileListener.class);
    private static final int BATCH_COUNT = 200;
    private static final int GROUP_BATCH_SIZE = 50; // 每批处理50个入库单
    private List<InboundImp> cached = new ArrayList<>(BATCH_COUNT);
    private AtomicInteger insertCount = new AtomicInteger(0);
    private AtomicInteger errorCount = new AtomicInteger(0);
    private AtomicInteger inboundCount = new AtomicInteger(0); // 入库单计数

    private CommonService commonService;
    private String namespace;
    private Map<String,Object> param;
    private List<String> errInfo = new ArrayList<>();
    private Map<String,Object> materialMap;
    // 用于存储按入库单号分组的明细数据
    private Map<String, List<InboundImp>> inboundGroupMap = new HashMap<>();
    private Map<String, Object> user = null;
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    public InboundFileListener(CommonService commonService, String namespace, Map<String,Object> param) {
        this.commonService = commonService;
        this.namespace = namespace;
        this.param = param;
        user = (Map<String, Object>) param.get("_user");
        // 初始化日期格式
        dateFormat.setLenient(false);
        // 初始化物料映射
        initMaterialMap();
    }

    /**
     * 初始化物料映射
     */
    private void initMaterialMap() {
        try {
            List<Map<String,Object>> materialList = commonService.findList(namespace + "getMaterialMap", null);
            materialMap = new HashMap<>();
            for (Map<String, Object> material : materialList) {
                String code = String.valueOf(material.get("material_code"));
                if (StringUtils.isNotEmpty(code)) {
                    materialMap.put(code, material);
                }
            }
            log.info("初始化物料映射完成，共 {} 条记录", materialMap.size());
        } catch (Exception e) {
            log.error("初始化物料映射异常", e);
            materialMap = new HashMap<>();
        }
    }

    @Override
    public void invoke(InboundImp data, AnalysisContext context) {
        try {
            // 数据校验
            if (isValidInbound(data)) {
                cached.add(data);
                // 按入库单号和批次号分组
                String groupKey = getGroupKey(data);

                // 初始化分组列表
                if (!inboundGroupMap.containsKey(groupKey)) {
                    inboundGroupMap.put(groupKey, new ArrayList<>());
                }
                inboundGroupMap.get(groupKey).add(data);
            } else {
                errorCount.incrementAndGet();
                errInfo.add("行数据校验失败: " + data.getInbound_no() + "-" + data.getMaterial_code());
            }

            if (cached.size() >= BATCH_COUNT) {
                saveBatch();
                cached.clear();
            }
        } catch (Exception e) {
            errorCount.incrementAndGet();
            errInfo.add("解析异常: " + data.getInbound_no() + "-" + data.getMaterial_code() + ":" + e.getMessage());
            log.error("解析入库导入行异常", e);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (!cached.isEmpty()) {
            saveBatch();
            cached.clear();
        }

        // 处理所有分组的数据
        processInboundGroupsTransactional();
    }

    /**
     * 获取分组键（入库单号 + 批次号）
     */
    private String getGroupKey(InboundImp data) {
        String inboundNo = StringUtils.isNotEmpty(data.getInbound_no()) ? data.getInbound_no().trim() : "";
        String batchNo = StringUtils.isNotEmpty(data.getBatch_no()) ? data.getBatch_no().trim() : "DEFAULT";
        return inboundNo + "|" + batchNo;
    }

    /**
     * 事务性批量处理入库单
     */
    private void processInboundGroupsTransactional() {
        if (inboundGroupMap.isEmpty()) {
            return;
        }

        List<String> groupKeys = new ArrayList<>(inboundGroupMap.keySet());

        // 按批次处理，避免内存溢出
        for (int i = 0; i < groupKeys.size(); i += GROUP_BATCH_SIZE) {
            int end = Math.min(i + GROUP_BATCH_SIZE, groupKeys.size());
            List<String> batchGroupKeys = groupKeys.subList(i, end);

            try {
                // 开启事务处理一批入库单
                processBatchTransactional(batchGroupKeys);
            } catch (Exception e) {
                log.error("批量处理入库单异常", e);
                // 当前批次失败，尝试单个处理
                for (String groupKey : batchGroupKeys) {
                    try {
                        processSingleInboundGroup(groupKey);
                    } catch (Exception ex) {
                        errorCount.incrementAndGet();
                        errInfo.add("入库单处理失败: " + groupKey + ":" + ex.getMessage());
                    }
                }
            }
        }
    }

    /**
     * 批量处理事务
     */
    private void processBatchTransactional(List<String> groupKeys) {
        List<Map<String, Object>> masterList = new ArrayList<>();
        Map<String, String> inboundIdMap = new HashMap<>(); // groupKey -> inboundId
        List<Map<String, Object>> detailList = new ArrayList<>();

        // 第一步：创建入库单主表和明细数据
        for (String groupKey : groupKeys) {
            List<InboundImp> inboundList = inboundGroupMap.get(groupKey);
            if (inboundList == null || inboundList.isEmpty()) {
                continue;
            }

            InboundImp firstRecord = inboundList.get(0);
            Map<String, Object> inboundMaster = createInboundMaster(firstRecord);
            if (inboundMaster == null) {
                throw new RuntimeException("创建入库单主表失败: " + groupKey);
            }

            String inboundId = (String) inboundMaster.get("id");
            inboundIdMap.put(groupKey, inboundId);
            masterList.add(inboundMaster);

            // 创建明细数据
            for (InboundImp detail : inboundList) {
                Map<String, Object> inboundDetail = createInboundDetail(detail, inboundId);
                if (inboundDetail != null) {
                    detailList.add(inboundDetail);
                }
            }
        }

        if (masterList.isEmpty()) {
            return;
        }

        // 第二步：批量插入入库单主表
        batchInsertInboundMasters(masterList);
        inboundCount.addAndGet(masterList.size());

        // 第三步：批量插入入库明细
        if (!detailList.isEmpty()) {
            batchInsertInboundDetails(detailList);
            insertCount.addAndGet(detailList.size());
        }

        // 第四步：批量更新物料库存
        batchUpdateMaterialStock(detailList);
    }

    /**
     * 单个入库单组处理
     */
    private void processSingleInboundGroup(String groupKey) {
        List<InboundImp> inboundList = inboundGroupMap.get(groupKey);
        if (inboundList == null || inboundList.isEmpty()) {
            return;
        }

        InboundImp firstRecord = inboundList.get(0);
        Map<String, Object> inboundMaster = createInboundMaster(firstRecord);
        if (inboundMaster == null) {
            throw new RuntimeException("创建入库单主表失败: " + groupKey);
        }

        // 插入主表
        String inboundId = insertInboundMaster(inboundMaster);
        if (inboundId == null) {
            throw new RuntimeException("插入入库单主表失败: " + groupKey);
        }

        inboundCount.incrementAndGet();

        // 插入明细
        for (InboundImp detail : inboundList) {
            Map<String, Object> inboundDetail = createInboundDetail(detail, inboundId);
            if (inboundDetail != null) {
                insertInboundDetail(inboundDetail);
                insertCount.incrementAndGet();
            }
        }
    }

    /**
     * 批量插入入库单主表
     */
    private void batchInsertInboundMasters(List<Map<String, Object>> inboundMasters) {
        if (inboundMasters == null || inboundMasters.isEmpty()) {
            return;
        }

        try {
            Map<String, Object> batchParam = new HashMap<>();
            batchParam.put("list", inboundMasters);
            batchParam.put("_user", user);

            commonService.insert(namespace + "batchInsertInboundMasters", batchParam);

        } catch (Exception e) {
            log.error("批量插入入库单主表异常", e);
            throw new RuntimeException("批量插入入库单主表失败", e);
        }
    }

    /**
     * 批量插入入库明细
     */
    private void batchInsertInboundDetails(List<Map<String, Object>> inboundDetails) {
        if (inboundDetails == null || inboundDetails.isEmpty()) {
            return;
        }

        try {
            Map<String, Object> batchParam = new HashMap<>();
            batchParam.put("list", inboundDetails);
            batchParam.put("_user", user);

            commonService.insert(namespace + "batchInsertInboundDetails", batchParam);

        } catch (Exception e) {
            log.error("批量插入入库明细异常", e);
            throw new RuntimeException("批量插入入库明细失败", e);
        }
    }

    /**
     * 批量更新物料库存
     */
    private void batchUpdateMaterialStock(List<Map<String, Object>> inboundDetails) {
        if (inboundDetails == null || inboundDetails.isEmpty()) {
            return;
        }

        try {
            // 按物料ID分组汇总数量
            Map<String, BigDecimal> materialQuantityMap = new HashMap<>();

            for (Map<String, Object> detail : inboundDetails) {
                String materialId = (String) detail.get("material_id");
                BigDecimal quantity = (BigDecimal) detail.get("inbound_quantity");

                if (materialId != null && quantity != null) {
                    materialQuantityMap.merge(materialId, quantity, BigDecimal::add);
                }
            }

            // 批量更新
            List<Map<String, Object>> updateList = new ArrayList<>();
            for (Map.Entry<String, BigDecimal> entry : materialQuantityMap.entrySet()) {
                Map<String, Object> updateParam = new HashMap<>();
                updateParam.put("material_id", entry.getKey());
                updateParam.put("quantity", entry.getValue());
                updateParam.put("update_time", new Date());
                updateParam.put("_user", user);
                updateList.add(updateParam);
            }

            if (!updateList.isEmpty()) {
                Map<String, Object> batchParam = new HashMap<>();
                batchParam.put("list", updateList);
                batchParam.put("_user", user);

                commonService.update(namespace + "batchUpdateMaterialStock", batchParam);
            }

        } catch (Exception e) {
            log.error("批量更新物料库存异常", e);
            throw new RuntimeException("批量更新物料库存失败", e);
        }
    }

    /**
     * 创建入库单主表记录
     */
    private Map<String, Object> createInboundMaster(InboundImp data) {
        try {
            Map<String, Object> master = new HashMap<>();
            master.put("id", UUIDUtil.getUUID());
            master.put("inbound_no", data.getInbound_no());
            master.put("batch_no", data.getBatch_no());
            master.put("inbound_type", 1);
            master.put("inbound_status", 1); // 1-已入库

            // 处理入库日期
            Date inboundDate = null;
            if (StringUtils.isNotEmpty(data.getInbound_date())) {
                try {
                    inboundDate = dateFormat.parse(data.getInbound_date().trim());
                } catch (ParseException e) {
                    log.warn("日期格式解析失败: {}", data.getInbound_date());
                }
            }
            if (inboundDate == null) {
                inboundDate = new Date();
            }
            master.put("inbound_date", inboundDate);
            master.put("is_used", 1);
            master.put("storage_location", data.getStorage_location());
            master.put("remark", data.getRemark());
            master.put("create_by", user.get("id"));
            master.put("create_time", new Date());
            master.put("_user", user);

            return master;
        } catch (Exception e) {
            log.error("创建入库单主表异常", e);
            return null;
        }
    }

    /**
     * 创建入库明细记录
     */
    private Map<String, Object> createInboundDetail(InboundImp data, String inboundId) {
        try {
            // 检查物料是否存在
            Map<String, Object> materialTempMap = (Map<String, Object>) materialMap.get(data.getMaterial_code());
            if (materialTempMap == null) {
                log.warn("物料 {} 不存在，跳过该明细", data.getMaterial_code());
                errInfo.add("物料不存在: " + data.getMaterial_code());
                return null;
            }

            Map<String, Object> detail = new HashMap<>();
            detail.put("id", UUIDUtil.getUUID());
            detail.put("inbound_id", inboundId);
            detail.put("material_id", materialTempMap.get("id"));

            // 物料名称优先使用Excel中的，否则使用系统已有的
            String materialName = StringUtils.isNotEmpty(data.getMaterial_name()) ?
                    data.getMaterial_name().trim() : (String) materialTempMap.get("material_name");
            detail.put("material_name", materialName);
            detail.put("material_code", data.getMaterial_code());
            detail.put("inbound_type", 1);
            detail.put("is_used", 1);
            // 转换入库数量
            BigDecimal inboundQuantity = BigDecimal.ZERO;
            try {
                if (StringUtils.isNotEmpty(data.getInbound_quantity())) {
                    inboundQuantity = new BigDecimal(data.getInbound_quantity().trim());
                }
            } catch (Exception e) {
                log.warn("数量格式转换失败: {}", data.getInbound_quantity());
                inboundQuantity = BigDecimal.ZERO;
            }
            detail.put("inbound_quantity", inboundQuantity);

            // 转换单价
            BigDecimal unitPrice = BigDecimal.ZERO;
            try {
                if (StringUtils.isNotEmpty(data.getUnit_price())) {
                    unitPrice = new BigDecimal(data.getUnit_price().trim());
                }
            } catch (Exception e) {
                log.warn("单价格式转换失败: {}", data.getUnit_price());
                unitPrice = BigDecimal.ZERO;
            }
            detail.put("unit_price", unitPrice);

            // 计算总金额
            BigDecimal totalAmount = inboundQuantity.multiply(unitPrice);
            detail.put("total_amount", totalAmount);

            // 处理生产日期
            Date productionDate = null;
            if (StringUtils.isNotEmpty(data.getProduction_date())) {
                try {
                    productionDate = dateFormat.parse(data.getProduction_date().trim());
                } catch (ParseException e) {
                    log.warn("生产日期格式解析失败: {}", data.getProduction_date());
                }
            }
            detail.put("production_date", productionDate);

            // 处理有效期
            Date expiryDate = null;
            if (StringUtils.isNotEmpty(data.getExpiry_date())) {
                try {
                    expiryDate = dateFormat.parse(data.getExpiry_date().trim());
                } catch (ParseException e) {
                    log.warn("有效期格式解析失败: {}", data.getExpiry_date());
                }
            }
            detail.put("expiry_date", expiryDate);

            detail.put("create_by", user.get("id"));
            detail.put("create_time", new Date());
            detail.put("_user", user);

            return detail;
        } catch (Exception e) {
            log.error("创建入库明细异常", e);
            return null;
        }
    }

    /**
     * 插入入库单主表
     */
    private String insertInboundMaster(Map<String, Object> inboundMaster) {
        try {
            commonService.insert(namespace + "insertInboundMaster", inboundMaster);
            return (String) inboundMaster.get("id");
        } catch (Exception e) {
            log.error("插入入库单主表异常", e);
            return null;
        }
    }

    /**
     * 插入入库明细
     */
    private void insertInboundDetail(Map<String, Object> inboundDetail) {
        try {
            commonService.insert(namespace + "insertInboundDetail", inboundDetail);
        } catch (Exception e) {
            log.error("插入入库明细异常", e);
            throw e;
        }
    }

    /**
     * 数据校验方法
     */
    private boolean isValidInbound(InboundImp data) {
        // 必需字段校验
        if (StringUtils.isEmpty(data.getInbound_no()) ||
                StringUtils.isEmpty(data.getMaterial_code()) ||
                StringUtils.isEmpty(data.getInbound_quantity())) {
            return false;
        }

        // 数量校验
        try {
            BigDecimal quantity = new BigDecimal(data.getInbound_quantity().trim());
            if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
                return false;
            }
        } catch (Exception e) {
            return false;
        }

        // 单价校验（可选）
        if (StringUtils.isNotEmpty(data.getUnit_price())) {
            try {
                new BigDecimal(data.getUnit_price().trim());
            } catch (Exception e) {
                return false;
            }
        }

        return true;
    }

    public Map<String,Object> getResult() {
        Map<String,Object> r = new HashMap<>();
        r.put("insert", insertCount.get()); // 明细条数
        r.put("inbound_count", inboundCount.get()); // 入库单数量
        r.put("error", errorCount.get());
        r.put("errInfo", errInfo.size() > 0 ? String.join(", ", errInfo) : "无");
        return r;
    }

    // 批量保存方法（如果需要保留原来的逻辑）
    private void saveBatch() {
        // 这里可以根据需要保留原有的批量处理逻辑
    }
}