package com.haha.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.exception.BusinessException;
import com.haha.entity.ErpGoods;
import com.haha.entity.Product;
import com.haha.mapper.ErpGoodsMapper;
import com.haha.mapper.ProductMapper;
import com.haha.service.ErpGoodsService;
import com.qdb.sdk.QdbClient;
import com.qdb.sdk.QdbException;
import com.qdb.sdk.model.request.SysGoodsQueryRequest;
import com.qdb.sdk.model.response.QdbResponse;
import com.qdb.sdk.model.response.SysGoodsVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Slf4j
@Service
@RequiredArgsConstructor
public class ErpGoodsServiceImpl extends ServiceImpl<ErpGoodsMapper, ErpGoods> implements ErpGoodsService {

    private final ProductMapper productMapper;

    @Autowired(required = false)
    private QdbClient qdbClient;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Async("taskExecutor")
    @Override
    public void syncFromErp() {
        if (qdbClient == null) {
            throw new BusinessException(500, "QdbClient 未配置，无法同步ERP商品数据");
        }

        List<Product> products = productMapper.selectList(new LambdaQueryWrapper<Product>()
                .eq(Product::getIsDeleted, 0)
                .isNotNull(Product::getName)
                .ne(Product::getName, ""));

        if (products.isEmpty()) {
            log.info("无本地商品需要同步");
            return;
        }

        log.info("开始逐条同步ERP商品: 共 {} 个本地商品", products.size());
        int syncedCount = 0;
        int total = products.size();
        List<String> missedNames = new java.util.ArrayList<>();

        for (int i = 0; i < total; i++) {
            Product product = products.get(i);
            String goodsCode = product.getName();

            try {
                SysGoodsQueryRequest request = SysGoodsQueryRequest.builder()
                        .pageIndex(1)
                        .pageSize(1)
                        .goodsCode(goodsCode)
                        .status(1)
                        .combination(0)
                        .build();

                QdbResponse<List<SysGoodsVO>> response = qdbClient.getGoodsApi()
                        .listSysGoods(request);
                List<SysGoodsVO> goodsList = response.getData();

                if (goodsList != null && !goodsList.isEmpty()) {
                    for (SysGoodsVO goods : goodsList) {
                        if (goods.getGoodsId() == null) {
                            log.warn("ERP返回的商品缺少goodsId, 跳过: goodsCode={}", goodsCode);
                            continue;
                        }
                        upsertErpGoods(goods);
                        syncedCount++;
                    }
                } else {
                    missedNames.add(goodsCode);
                }

            } catch (QdbException e) {
                log.error("查询ERP商品失败: goodsCode={}, error={}", goodsCode, e.getMessage());
                missedNames.add(goodsCode);
            }

            if ((i + 1) % 10 == 0 && i + 1 < total) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }

        log.info("ERP商品同步完成: 处理 {} 条, 命中 {} 条, 未找到 {} 条", total, syncedCount, missedNames.size());
        if (!missedNames.isEmpty()) {
            log.info("以下商品在ERP中未找到 ({} 条):\n{}",
                    missedNames.size(), String.join("\n", missedNames));
        }
    }

    @Override
    public IPage<ErpGoods> listAll(String keyword, int page, int pageSize) {
        LambdaQueryWrapper<ErpGoods> wrapper = new LambdaQueryWrapper<ErpGoods>()
                .eq(ErpGoods::getStatus, 1);
        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w
                    .like(ErpGoods::getGoodsName, keyword)
                    .or()
                    .like(ErpGoods::getGoodsCode, keyword));
        }
        return page(new Page<>(page, pageSize), wrapper.orderByAsc(ErpGoods::getGoodsName));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindGoods(Long productId, Long erpGoodsId) {
        Product product = productMapper.selectById(productId);
        if (product == null) {
            throw new BusinessException(404, "商品不存在");
        }

        ErpGoods erpGoods = getOne(new LambdaQueryWrapper<ErpGoods>()
                .eq(ErpGoods::getErpGoodsId, erpGoodsId));
        if (erpGoods == null) {
            throw new BusinessException(404, "ERP商品不存在，请先同步ERP商品数据");
        }

        List<Product> boundProducts = productMapper.selectList(new LambdaQueryWrapper<Product>()
                .eq(Product::getErpGoodsId, erpGoodsId)
                .eq(Product::getIsDeleted, 0));
        if (!boundProducts.isEmpty() && !boundProducts.get(0).getId().equals(productId)) {
            throw new BusinessException(400, "该ERP商品已关联到本地商品: " + boundProducts.get(0).getName());
        }

        product.setErpGoodsId(erpGoodsId);
        product.setUpdateTime(LocalDateTime.now());
        productMapper.updateById(product);

        log.info("商品关联ERP商品: productId={}, productName={}, erpGoodsId={}, erpGoodsName={}",
                productId, product.getName(), erpGoodsId, erpGoods.getGoodsName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbindGoods(Long productId) {
        Product product = productMapper.selectById(productId);
        if (product == null) {
            throw new BusinessException(404, "商品不存在");
        }

        productMapper.update(null, new LambdaUpdateWrapper<Product>()
                .set(Product::getErpGoodsId, null)
                .set(Product::getUpdateTime, LocalDateTime.now())
                .eq(Product::getId, productId));

        log.info("商品解除ERP商品关联: productId={}, productName={}", productId, product.getName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Integer> autoBind() {
        List<ErpGoods> erpGoodsList = list(new LambdaQueryWrapper<ErpGoods>()
                .eq(ErpGoods::getStatus, 1));
        if (erpGoodsList.isEmpty()) {
            Map<String, Integer> empty = new HashMap<>();
            empty.put("bound", 0);
            empty.put("skipped", 0);
            return empty;
        }

        // 1. 收集所有 ERP 商品 ID，批量查已关联的本地商品
        List<Long> allErpGoodsIds = erpGoodsList.stream().map(ErpGoods::getErpGoodsId).toList();
        Set<Long> boundErpGoodsIds = new HashSet<>(productMapper.selectList(new LambdaQueryWrapper<Product>()
                .in(Product::getErpGoodsId, allErpGoodsIds)
                .eq(Product::getIsDeleted, 0))
                .stream().map(Product::getErpGoodsId).toList());

        // 2. 收集未关联的 ERP 商品 code，批量查本地商品
        Map<String, Long> codeToErpGoodsId = new LinkedHashMap<>();
        for (ErpGoods erp : erpGoodsList) {
            if (!boundErpGoodsIds.contains(erp.getErpGoodsId())) {
                codeToErpGoodsId.put(erp.getGoodsCode(), erp.getErpGoodsId());
            }
        }
        int alreadyBoundSkip = erpGoodsList.size() - codeToErpGoodsId.size();

        // 3. 分批查本地商品（每批 100 个 code）
        Map<String, List<Product>> nameToProducts = new HashMap<>();
        List<String> allCodes = new ArrayList<>(codeToErpGoodsId.keySet());
        for (int i = 0; i < allCodes.size(); i += 100) {
            int end = Math.min(i + 100, allCodes.size());
            List<String> batch = allCodes.subList(i, end);
            List<Product> batchProducts = productMapper.selectList(new LambdaQueryWrapper<Product>()
                    .in(Product::getName, batch)
                    .eq(Product::getIsDeleted, 0));
            for (Product p : batchProducts) {
                nameToProducts.computeIfAbsent(p.getName(), k -> new ArrayList<>()).add(p);
            }
        }

        // 4. 收集唯一匹配的关联对
        java.util.List<Long> bindProductIds = new ArrayList<>();
        java.util.List<Long> bindErpIds = new ArrayList<>();
        int skipped = alreadyBoundSkip;

        for (Map.Entry<String, Long> entry : codeToErpGoodsId.entrySet()) {
            String goodsCode = entry.getKey();
            Long erpGoodsId = entry.getValue();
            List<Product> matches = nameToProducts.getOrDefault(goodsCode, List.of());

            if (matches.size() == 1) {
                bindProductIds.add(matches.get(0).getId());
                bindErpIds.add(erpGoodsId);
                log.info("自动关联: erpGoodsCode={}, productName={}", goodsCode, matches.get(0).getName());
            } else {
                skipped++;
            }
        }

        // 5. 批量 UPDATE 用 CASE WHEN（100 条一批）
        int bound = 0;
        for (int i = 0; i < bindProductIds.size(); i += 100) {
            int end = Math.min(i + 100, bindProductIds.size());
            List<Long> batchIds = bindProductIds.subList(i, end);
            List<Long> batchErpIds = bindErpIds.subList(i, end);

            StringBuilder sql = new StringBuilder(
                    "UPDATE t_product SET erp_goods_id = CASE id ");
            for (int j = 0; j < batchIds.size(); j++) {
                sql.append("WHEN ").append(batchIds.get(j))
                   .append(" THEN ").append(batchErpIds.get(j)).append(" ");
            }
            sql.append("END, update_time = NOW() WHERE id IN (");
            for (int j = 0; j < batchIds.size(); j++) {
                if (j > 0) sql.append(",");
                sql.append(batchIds.get(j));
            }
            sql.append(")");

            bound += jdbcTemplate.update(sql.toString());
        }

        log.info("一键自动关联完成: 成功 {} 条, 跳过 {} 条", bound, skipped);
        Map<String, Integer> result = new HashMap<>();
        result.put("bound", bound);
        result.put("skipped", skipped);
        return result;
    }

    private void upsertErpGoods(SysGoodsVO goods) {
        log.info("同步ERP商品: goodsId={}, goodsCode={}, goodsName={}",
                goods.getGoodsId(), goods.getGoodsCode(), goods.getGoodsName());
        ErpGoods existing = getOne(new LambdaQueryWrapper<ErpGoods>()
                .eq(ErpGoods::getErpGoodsId, goods.getGoodsId()));

        if (existing != null) {
            existing.setGoodsCode(goods.getGoodsCode());
            existing.setGoodsName(goods.getGoodsName());
            existing.setShortGoodsName(goods.getShortGoodsName());
            existing.setSpecs(goods.getSpecs());
            existing.setSkUnit(goods.getSkUnit());
            existing.setGoodsKindCode(goods.getGoodsKindCode());
            existing.setGoodsKindName(goods.getGoodsKindName());
            existing.setBrand(goods.getBrand());
            existing.setSalePrice(goods.getSalePrice());
            existing.setCostPrice(goods.getCostPrice());
            existing.setProviderName(goods.getProviderName());
            existing.setBatchType(goods.getBatchType());
            existing.setCombination(goods.getCombination());
            existing.setArticleNo(goods.getArticleNo());
            existing.setPicPath(goods.getPicPath());
            existing.setWeight(goods.getWeight());
            existing.setBarCode(goods.getBarCodeList() != null && !goods.getBarCodeList().isEmpty()
                    ? JSON.toJSONString(goods.getBarCodeList()) : null);
            if (goods.getModifyDate() != null) {
                existing.setModifyDate(goods.getModifyDate().toInstant()
                        .atZone(ZoneId.systemDefault()).toLocalDateTime());
            }
            existing.setUpdateTime(LocalDateTime.now());
            updateById(existing);
        } else {
            ErpGoods erpGoods = new ErpGoods();
            erpGoods.setErpGoodsId(goods.getGoodsId());
            erpGoods.setGoodsCode(goods.getGoodsCode());
            erpGoods.setGoodsName(goods.getGoodsName());
            erpGoods.setShortGoodsName(goods.getShortGoodsName());
            erpGoods.setSpecs(goods.getSpecs());
            erpGoods.setSkUnit(goods.getSkUnit());
            erpGoods.setGoodsKindCode(goods.getGoodsKindCode());
            erpGoods.setGoodsKindName(goods.getGoodsKindName());
            erpGoods.setBrand(goods.getBrand());
            erpGoods.setSalePrice(goods.getSalePrice());
            erpGoods.setCostPrice(goods.getCostPrice());
            erpGoods.setProviderName(goods.getProviderName());
            erpGoods.setBatchType(goods.getBatchType());
            erpGoods.setCombination(goods.getCombination());
            erpGoods.setArticleNo(goods.getArticleNo());
            erpGoods.setPicPath(goods.getPicPath());
            erpGoods.setWeight(goods.getWeight());
            erpGoods.setBarCode(goods.getBarCodeList() != null && !goods.getBarCodeList().isEmpty()
                    ? JSON.toJSONString(goods.getBarCodeList()) : null);
            if (goods.getModifyDate() != null) {
                erpGoods.setModifyDate(goods.getModifyDate().toInstant()
                        .atZone(ZoneId.systemDefault()).toLocalDateTime());
            }
            erpGoods.setStatus(1);
            erpGoods.setCreateTime(LocalDateTime.now());
            erpGoods.setUpdateTime(LocalDateTime.now());
            save(erpGoods);
        }
    }
}
