package com.haha.service.impl;

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.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.haha.common.dto.FloorConfig;
import com.haha.common.dto.GoodsItem;
import com.haha.common.dto.LayerTemplateCreateDTO;
import com.haha.common.dto.LayerTemplateUpdateDTO;
import com.haha.common.constant.CommonConstants;
import com.haha.common.constant.SyncConstants;
import com.haha.common.exception.BusinessException;
import com.haha.common.utils.EntityLabelUtils;
import com.haha.entity.Device;
import com.haha.entity.DeviceInventory;
import com.haha.entity.InventoryLog;
import com.haha.entity.LayerTemplate;
import com.haha.entity.Product;
import com.haha.mapper.DeviceMapper;
import com.haha.mapper.LayerTemplateMapper;
import com.haha.sdk.HahaClient;
import com.haha.sdk.api.GoodsApi;
import com.haha.service.DeviceInventoryService;
import com.haha.service.InventoryLogService;
import com.haha.service.LayerTemplateService;
import com.haha.service.ProductService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 设备模版管理服务实现类
 * 支持层模版(LAYER)和柜模版(CABINET)两种类型
 * 提供设备模版的CRUD和同步功能，同步时自动检测模版类型
 *
 * @author haha-service
 * @version 2.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LayerTemplateServiceImpl extends ServiceImpl<LayerTemplateMapper, LayerTemplate> implements LayerTemplateService {

    private final HahaClient hahaClient;
    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private DeviceInventoryService deviceInventoryService;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private ProductService productService;

    /**
     * 分页查询层模版列表
     * 支持按设备ID、同步状态、模板名称进行筛选
     *
     * @param page         页码
     * @param pageSize     每页条数
     * @param deviceId     设备ID（可选）
     * @param syncStatus   同步状态（可选）
     * @param templateName 模板名称（可选）
     * @return 分页结果（已填充展示标签）
     */
    @Override
    public IPage<LayerTemplate> getPage(int page, int pageSize, String deviceId, Integer syncStatus, String templateName, String templateType) {
        log.info("分页查询设备模版: page={}, pageSize={}, deviceId={}, syncStatus={}, templateName={}, templateType={}",
                page, pageSize, deviceId, syncStatus, templateName, templateType);

        LambdaQueryWrapper<LayerTemplate> wrapper = new LambdaQueryWrapper<>();

        // 构建查询条件
        wrapper.like(deviceId != null && !deviceId.isEmpty(), LayerTemplate::getDeviceId, deviceId)
               .eq(syncStatus != null, LayerTemplate::getSyncStatus, syncStatus)
               .like(templateName != null && !templateName.isEmpty(), LayerTemplate::getTemplateName, templateName)
               .eq(templateType != null && !templateType.isEmpty(), LayerTemplate::getTemplateType, templateType)
               .eq(LayerTemplate::getIsDeleted, CommonConstants.NOT_DELETED)
               .orderByDesc(LayerTemplate::getCreateTime);

        // 执行分页查询
        IPage<LayerTemplate> pageResult = this.page(new Page<>(page, pageSize), wrapper);

        log.info("设备模版查询结果: total={}, records={}", pageResult.getTotal(), pageResult.getRecords().size());

        // 填充展示字段（同步状态标签、设备类型等）
        pageResult.getRecords().forEach(this::fillLabels);

        return pageResult;
    }

    /**
     * 获取层模版详情
     * 包含完整的展示字段填充
     *
     * @param id 层模版ID
     * @return 层模版详情
     */
    @Override
    public LayerTemplate getDetailById(Long id) {
        log.info("获取层模版详情: id={}", id);

        LayerTemplate layerTemplate = this.getById(id);
        if (layerTemplate == null) {
            log.warn("层模版不存在: id={}", id);
            return null;
        }

        // 填充展示字段
        fillLabels(layerTemplate);

        return layerTemplate;
    }

    /**
     * 根据设备ID获取层模版
     * 一个设备通常对应一个层模版配置
     *
     * @param deviceId 设备ID（SN号）
     * @return 层模版信息
     */
    @Override
    public LayerTemplate getByDeviceId(String deviceId) {
        log.info("根据设备ID获取层模版: deviceId={}", deviceId);

        LambdaQueryWrapper<LayerTemplate> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LayerTemplate::getDeviceId, deviceId)
               .eq(LayerTemplate::getIsDeleted, CommonConstants.NOT_DELETED)
               .orderByDesc(LayerTemplate::getCreateTime)
               .last("LIMIT 1");

        LayerTemplate layerTemplate = this.getOne(wrapper);
        if (layerTemplate != null) {
            fillLabels(layerTemplate);
        }

        return layerTemplate;
    }

    /**
     * 创建层模版
     * 将前端提交的层模版数据保存到本地数据库
     *
     * @param dto 创建请求DTO
     * @return 创建后的层模版
     */
    @Override
    public LayerTemplate create(LayerTemplateCreateDTO dto) {
        log.info("创建层模版: deviceId={}, templateName={}", dto.getDeviceId(), dto.getTemplateName());

        // 检查是否已存在该设备的层模版
        LayerTemplate existing = this.getByDeviceId(dto.getDeviceId());
        if (existing != null) {
            throw new BusinessException(400, "该设备已存在层模版配置");
        }

        // 转换DTO为实体对象
        LayerTemplate layerTemplate = convertFromCreateDto(dto);

        // 设置基础字段
        layerTemplate.setIsDeleted(CommonConstants.NOT_DELETED);
        layerTemplate.setSyncStatus(SyncConstants.STATUS_NOT_SYNCED);
        layerTemplate.setCreateTime(LocalDateTime.now());
        layerTemplate.setUpdateTime(LocalDateTime.now());

        // 保存到数据库
        this.save(layerTemplate);

        log.info("层模版创建成功: id={}, deviceId={}", layerTemplate.getId(), layerTemplate.getDeviceId());

        // 重算标准库存
        try {
            deviceInventoryService.recalculateStandardStock(dto.getDeviceId());
        } catch (Exception e) {
            log.error("层模版创建后重算标准库存失败: deviceId={}, error={}", dto.getDeviceId(), e.getMessage());
        }

        fillLabels(layerTemplate);
        return layerTemplate;
    }

    /**
     * 更新层模版
     * 支持更新模板名称和层数据配置
     *
     * @param id  层模版ID
     * @param dto 更新请求DTO
     * @return 更新后的层模版
     */
    @Override
    public LayerTemplate update(Long id, LayerTemplateUpdateDTO dto) {
        log.info("更新层模版: id={}", id);

        LayerTemplate existing = this.getById(id);
        if (existing == null) {
            throw new BusinessException(404, "层模版不存在");
        }

        // 更新可编辑字段
        if (dto.getTemplateName() != null) {
            existing.setTemplateName(dto.getTemplateName());
        }
        if (dto.getTemplateType() != null) {
            existing.setTemplateType(dto.getTemplateType());
        }
        if (dto.getLeftFloors() != null && !dto.getLeftFloors().isEmpty()) {
            try {
                existing.setLeftFloors(objectMapper.writeValueAsString(dto.getLeftFloors()));
            } catch (JsonProcessingException e) {
                log.error("左门层数据JSON序列化失败", e);
                throw new BusinessException(500, "数据格式错误");
            }
        }
        if (dto.getRightFloors() != null && !dto.getRightFloors().isEmpty()) {
            try {
                existing.setRightFloors(objectMapper.writeValueAsString(dto.getRightFloors()));
            } catch (JsonProcessingException e) {
                log.error("右门层数据JSON序列化失败", e);
                throw new BusinessException(500, "数据格式错误");
            }
        }

        // 更新时间戳和同步状态标记
        existing.setUpdateTime(LocalDateTime.now());
        existing.setSyncStatus(SyncConstants.STATUS_NOT_SYNCED); // 标记为需要重新同步

        this.updateById(existing);

        log.info("层模版更新成功: id={}", id);

        // 重算标准库存
        try {
            deviceInventoryService.recalculateStandardStock(existing.getDeviceId());
        } catch (Exception e) {
            log.error("层模版更新后重算标准库存失败: deviceId={}, error={}", existing.getDeviceId(), e.getMessage());
        }

        fillLabels(existing);
        return existing;
    }

    /**
     * 软删除层模版
     * 仅标记删除状态，不物理删除数据
     *
     * @param id 层模版ID
     * @return 是否成功
     */
    @Override
    public boolean softDelete(Long id) {
        log.info("软删除层模版: id={}", id);

        LayerTemplate layerTemplate = this.getById(id);
        if (layerTemplate == null) {
            throw new BusinessException(404, "层模版不存在");
        }

        LambdaUpdateWrapper<LayerTemplate> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(LayerTemplate::getId, id)
                     .set(LayerTemplate::getIsDeleted, CommonConstants.DELETED)
                     .set(LayerTemplate::getUpdateTime, LocalDateTime.now());

        boolean result = this.update(updateWrapper);

        log.info("层模版软删除结果: id={}, result={}", id, result);

        // 重算标准库存（删除后标准库存可能归零）
        try {
            deviceInventoryService.recalculateStandardStock(layerTemplate.getDeviceId());
        } catch (Exception e) {
            log.error("层模版删除后重算标准库存失败: deviceId={}, error={}", layerTemplate.getDeviceId(), e.getMessage());
        }

        return result;
    }

    /**
     * 从哈哈平台同步单个设备层模版
     * 这是核心同步逻辑：
     * 1. 更新状态为"同步中"
     * 2. 调用GoodsApi获取平台数据
     * 3. 解析并转换数据
     * 4. 更新或创建本地记录
     * 5. 更新同步状态和时间
     * 6. 异常处理确保状态正确更新
     *
     * @param deviceId 设备ID（SN号）
     * @return 是否成功
     */
    @Override
    public boolean syncFromHaha(String deviceId) {
        log.info("开始同步层模版: deviceId={}", deviceId);

        // 步骤1: 查询或创建本地记录，并更新状态为"同步中"
        LayerTemplate localTemplate = this.getByDeviceId(deviceId);
        boolean isNewRecord = false;

        if (localTemplate == null) {
            // 不存在则创建新记录
            localTemplate = new LayerTemplate();
            localTemplate.setDeviceId(deviceId);
            localTemplate.setIsDeleted(CommonConstants.NOT_DELETED);
            localTemplate.setCreateTime(LocalDateTime.now());
            isNewRecord = true;
        }

        // 更新状态为"同步中"
        updateSyncStatus(deviceId, SyncConstants.STATUS_SYNCING, null);

        try {
            // 步骤2: 自动检测模版类型并调用对应API
            GoodsApi goodsApi = hahaClient.getGoodsApi();
            Map<String, Object> apiData = null;
            String detectedTemplateType = null;

            // 先尝试层模版 API (4.5.1)，失败或数据无效则尝试柜模版 API (4.1)
            // 注意：BaseApi.post() 只在 code != 1 时抛 HahaException
            // 如果平台对柜模版设备返回 code=1 但 data 为空，抛异常也不会触发
            // 所以必须同时验证返回数据是否包含层模版特有字段
            boolean layerValid = false;
            try {
                apiData = goodsApi.getLayerTemplate(deviceId);
                // 验证返回数据是否为有效的层模版
                // products 必须是 Map 且非空，不能是空字符串（柜模版设备会返回 products:""）
                layerValid = apiData != null
                        && apiData.get("products") instanceof Map
                        && !((Map<?, ?>) apiData.get("products")).isEmpty();
                if (layerValid) {
                    detectedTemplateType = SyncConstants.TEMPLATE_TYPE_LAYER;
                    log.info("设备 {} 检测为层模版(LAYER)类型，数据: {}", deviceId, apiData);
                } else {
                    log.info("层模版API返回成功但数据为空/无效(缺少products字段)，降级为柜模版: deviceId={}", deviceId);
                }
            } catch (Exception layerEx) {
                log.info("层模版API调用失败(code!=1)，尝试柜模版API: deviceId={}, error={}", deviceId, layerEx.getMessage());
            }

            if (!layerValid) {
                try {
                    apiData = goodsApi.getCabinetTemplate(deviceId);
                    detectedTemplateType = SyncConstants.TEMPLATE_TYPE_CABINET;
                    log.info("设备 {} 检测为柜模版(CABINET)类型，数据: {}", deviceId, apiData);
                } catch (Exception cabinetEx) {
                    log.error("柜模版API也调用失败: deviceId={}, error={}", deviceId, cabinetEx.getMessage());
                    throw new BusinessException(500, "无法获取设备模版数据，层模版和柜模版API均失败");
                }
            }

            // 步骤3-4: 根据模版类型解析数据并转换为实体对象
            LayerTemplate updatedTemplate;
            if (SyncConstants.TEMPLATE_TYPE_CABINET.equals(detectedTemplateType)) {
                updatedTemplate = convertCabinetFromApiData(deviceId, apiData);
            } else {
                updatedTemplate = convertFromApiData(deviceId, apiData);
            }
            updatedTemplate.setTemplateType(detectedTemplateType);

            // 步骤5: 更新或创建本地记录
            if (isNewRecord) {
                // 新记录，设置所有字段
                localTemplate.setTemplateId(updatedTemplate.getTemplateId());
                localTemplate.setTemplateName(updatedTemplate.getTemplateName());
                localTemplate.setDeviceType(updatedTemplate.getDeviceType());
                localTemplate.setShelfNum(updatedTemplate.getShelfNum());
                localTemplate.setLeftFloors(updatedTemplate.getLeftFloors());
                localTemplate.setRightFloors(updatedTemplate.getRightFloors());
                localTemplate.setGoodsRule(updatedTemplate.getGoodsRule());
                localTemplate.setTemplateType(detectedTemplateType);
                localTemplate.setSyncTime(LocalDateTime.now());
                localTemplate.setUpdateTime(LocalDateTime.now());

                this.save(localTemplate);
                log.info("新建设备模版记录: id={}, deviceId={}, templateType={}",
                        localTemplate.getId(), deviceId, detectedTemplateType);
            } else {
                // 已存在记录，更新数据
                LambdaUpdateWrapper<LayerTemplate> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(LayerTemplate::getDeviceId, deviceId)
                             .set(LayerTemplate::getTemplateId, updatedTemplate.getTemplateId())
                             .set(LayerTemplate::getTemplateName, updatedTemplate.getTemplateName())
                             .set(LayerTemplate::getDeviceType, updatedTemplate.getDeviceType())
                             .set(LayerTemplate::getShelfNum, updatedTemplate.getShelfNum())
                             .set(LayerTemplate::getLeftFloors, updatedTemplate.getLeftFloors())
                             .set(LayerTemplate::getRightFloors, updatedTemplate.getRightFloors())
                             .set(LayerTemplate::getGoodsRule, updatedTemplate.getGoodsRule())
                             .set(LayerTemplate::getTemplateType, detectedTemplateType)
                             .set(LayerTemplate::getUpdateTime, LocalDateTime.now());

                this.update(updateWrapper);
                log.info("更新设备模版记录: deviceId={}, templateType={}", deviceId, detectedTemplateType);
            }

            // 步骤6: 从层模版数据初始化库存（仅对尚不存在的商品创建 stock=0 记录）
            try {
                initInventoryFromTemplate(deviceId, apiData);
            } catch (Exception e) {
                log.error("层模版同步后初始化库存失败: deviceId={}", deviceId, e);
            }

            // 步骤6.5: 重算标准库存（同步后标准库存可能与层模版一致）
            try {
                deviceInventoryService.recalculateStandardStock(deviceId);
            } catch (Exception e) {
                log.error("层模版同步后重算标准库存失败: deviceId={}, error={}", deviceId, e.getMessage());
            }

            // 步骤7: 更新同步状态为"已同步"并记录时间
            updateSyncStatus(deviceId, SyncConstants.STATUS_SYNCED, LocalDateTime.now());

            log.info("设备模版同步成功: deviceId={}, templateType={}", deviceId, detectedTemplateType);
            return true;

        } catch (Exception e) {
            log.error("层模版同步失败: deviceId={}, error={}", deviceId, e.getMessage(), e);

            // 步骤7: 异常处理 - 更新状态为"同步失败"
            updateSyncStatus(deviceId, SyncConstants.STATUS_SYNC_FAILED, null);

            return false;
        }
    }

    /**
     * 批量同步设备层模版
     * 遍历设备列表逐个执行同步操作，并统计结果
     *
     * @param deviceIds 设备ID列表
     * @return 同步结果统计（包含成功数、失败数、总耗时等）
     */
    @Override
    public Map<String, Object> batchSync(List<String> deviceIds) {
        log.info("开始批量同步层模版: totalDevices={}", deviceIds.size());

        long startTime = System.currentTimeMillis();
        int successCount = 0;
        int failCount = 0;
        List<String> failedDeviceIds = new java.util.ArrayList<>();

        for (String deviceId : deviceIds) {
            boolean success = this.syncFromHaha(deviceId);
            if (success) {
                successCount++;
            } else {
                failCount++;
                failedDeviceIds.add(deviceId);
            }
        }

        long endTime = System.currentTimeMillis();
        long costTime = endTime - startTime;

        // 构建统计结果
        Map<String, Object> result = new HashMap<>();
        result.put("totalDevices", deviceIds.size());
        result.put("successCount", successCount);
        result.put("failCount", failCount);
        result.put("failedDeviceIds", failedDeviceIds);
        result.put("costTime", costTime);
        result.put("costTimeDisplay", formatCostTime(costTime));

        log.info("批量同步完成: total={}, success={}, fail={}, cost={}ms",
                deviceIds.size(), successCount, failCount, costTime);

        return result;
    }

    // ==================== 私有工具方法 ====================

    /**
     * 将API返回的Map数据转换为实体对象
     * 解析哈哈平台返回的层模版数据结构
     *
     * @param deviceId 设备ID
     * @param apiData  API返回的数据Map
     * @return 转换后的实体对象
     */
    private LayerTemplate convertFromApiData(String deviceId, Map<String, Object> apiData) {
        LayerTemplate template = new LayerTemplate();
        template.setDeviceId(deviceId);

        // 提取基本字段
        if (apiData.containsKey("template_id")) {
            template.setTemplateId(String.valueOf(apiData.get("template_id")));
        }
        if (apiData.containsKey("name")) {
            template.setTemplateName(String.valueOf(apiData.get("name")));
        }
        if (apiData.containsKey("type")) {
            Object typeObj = apiData.get("type");
            if (typeObj instanceof Number) {
                template.setDeviceType(((Number) typeObj).intValue());
            } else if (typeObj != null) {
                try {
                    template.setDeviceType(Integer.parseInt(typeObj.toString()));
                } catch (NumberFormatException e) {
                    log.warn("解析deviceType失败: {}", typeObj);
                }
            }
        }
        if (apiData.containsKey("shelf_num")) {
            Object shelfNumObj = apiData.get("shelf_num");
            if (shelfNumObj instanceof Number) {
                template.setShelfNum(((Number) shelfNumObj).intValue());
            } else if (shelfNumObj != null) {
                try {
                    template.setShelfNum(Integer.parseInt(shelfNumObj.toString()));
                } catch (NumberFormatException e) {
                    log.warn("解析shelfNum失败: {}", shelfNumObj);
                }
            }
        }

        // 提取products中的left/right数据（关键！）
        if (apiData.containsKey("products")) {
            Object productsObj = apiData.get("products");
            if (productsObj instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> products = (Map<String, Object>) productsObj;

                // 左门层数据 -> JSON字符串存储
                if (products.containsKey("left")) {
                    Object leftObj = products.get("left");
                    try {
                        template.setLeftFloors(objectMapper.writeValueAsString(leftObj));
                        log.debug("左门层数据转换成功: deviceId={}", deviceId);
                    } catch (JsonProcessingException e) {
                        log.error("左门层数据JSON序列化失败: deviceId={}", deviceId, e);
                    }
                }

                // 右门层数据 -> JSON字符串存储
                if (products.containsKey("right")) {
                    Object rightObj = products.get("right");
                    try {
                        template.setRightFloors(objectMapper.writeValueAsString(rightObj));
                        log.debug("右门层数据转换成功: deviceId={}", deviceId);
                    } catch (JsonProcessingException e) {
                        log.error("右门层数据JSON序列化失败: deviceId={}", deviceId, e);
                    }
                }
            }
        }

        // 商品规则（如果存在）
        if (apiData.containsKey("goods_rule")) {
            Object goodsRuleObj = apiData.get("goods_rule");
            if (goodsRuleObj != null) {
                try {
                    template.setGoodsRule(objectMapper.writeValueAsString(goodsRuleObj));
                } catch (JsonProcessingException e) {
                    log.warn("商品规则JSON序列化失败: deviceId={}", deviceId, e);
                    template.setGoodsRule(goodsRuleObj.toString());
                }
            }
        }

        return template;
    }

    /**
     * 将柜模版 API (4.1) 返回数据转换为实体对象
     * 柜模版没有层的概念，将4.1返回的分类商品列表展平为单层结构
     *
     * @param deviceId 设备ID
     * @param apiData  API返回的柜模版数据
     * @return 转换后的实体对象
     */
    private LayerTemplate convertCabinetFromApiData(String deviceId, Map<String, Object> apiData) {
        LayerTemplate template = new LayerTemplate();
        template.setDeviceId(deviceId);
        template.setTemplateType(SyncConstants.TEMPLATE_TYPE_CABINET);

        // 柜模版无层数概念
        template.setShelfNum(null);

        // 将 dataInfo 中的所有商品展平为单个虚拟层
        List<FloorConfig> floors = new ArrayList<>();
        FloorConfig singleFloor = new FloorConfig();
        singleFloor.setFloor(1);
        List<GoodsItem> goodsList = new ArrayList<>();

        if (apiData.containsKey("dataInfo")) {
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> dataInfoList = (List<Map<String, Object>>) apiData.get("dataInfo");
            if (dataInfoList != null) {
                for (Map<String, Object> category : dataInfoList) {
                    @SuppressWarnings("unchecked")
                    List<Map<String, Object>> goods = (List<Map<String, Object>>) category.get("goods");
                    if (goods != null) {
                        for (Map<String, Object> item : goods) {
                            GoodsItem goodsItem = new GoodsItem();
                            goodsItem.setKey(String.valueOf(item.getOrDefault("code", "")));
                            goodsItem.setLabel(String.valueOf(item.getOrDefault("name", "")));
                            goodsItem.setPic(String.valueOf(item.getOrDefault("pic", "")));
                            goodsItem.setRec_pic(String.valueOf(item.getOrDefault("rec_pic", "")));
                            Object cPrice = item.get("c_price");
                            if (cPrice != null) {
                                goodsItem.setC_price(String.valueOf(cPrice));
                            }
                            Object discount = item.get("discount");
                            if (discount != null) {
                                goodsItem.setDiscount(String.valueOf(discount));
                            }
                            Object disPrice = item.get("dis_price");
                            if (disPrice != null && !String.valueOf(disPrice).isEmpty()) {
                                goodsItem.setDis_price(String.valueOf(disPrice));
                            }
                            goodsItem.setType(String.valueOf(item.getOrDefault("type", "")));
                            goodsItem.setStock(0); // 柜模版中stock始终为0，由实际库存决定
                            goodsList.add(goodsItem);
                        }
                    }
                }
            }
        }

        singleFloor.setGoods(goodsList);
        floors.add(singleFloor);

        try {
            template.setLeftFloors(objectMapper.writeValueAsString(floors));
        } catch (JsonProcessingException e) {
            log.error("柜模版左门层数据JSON序列化失败: deviceId={}", deviceId, e);
        }

        // 柜模版没有右门
        template.setRightFloors(null);

        log.info("柜模版数据转换完成: deviceId={}, 商品数={}", deviceId, goodsList.size());
        return template;
    }

    /**
     * 将前端DTO转换为提交给平台的JSON格式
     * 用于将本地修改后的层模版数据推送到哈哈平台
     *
     * @param dto 前端提交的创建DTO
     * @return 平台所需的JSON格式字符串
     */
    private String convertToPlatformJson(LayerTemplateCreateDTO dto) {
        try {
            Map<String, Object> platformData = new HashMap<>();
            
            // 构建products结构
            Map<String, Object> products = new HashMap<>();
            products.put("left", dto.getLeftFloors());
            products.put("right", dto.getRightFloors() != null ? dto.getRightFloors() : List.of());
            
            platformData.put("products", products);
            platformData.put("name", dto.getTemplateName());
            
            return objectMapper.writeValueAsString(platformData);
        } catch (JsonProcessingException e) {
            log.error("转换为平台JSON格式失败", e);
            throw new BusinessException(500, "数据格式转换失败");
        }
    }

    /**
     * 将创建DTO转换为实体对象
     *
     * @param dto 创建请求DTO
     * @return 实体对象
     */
    private LayerTemplate convertFromCreateDto(LayerTemplateCreateDTO dto) {
        LayerTemplate template = new LayerTemplate();
        template.setDeviceId(dto.getDeviceId());
        template.setTemplateName(dto.getTemplateName());
        template.setTemplateType(dto.getTemplateType() != null ? dto.getTemplateType() : SyncConstants.TEMPLATE_TYPE_LAYER);

        // 序列化左门层数据
        if (dto.getLeftFloors() != null && !dto.getLeftFloors().isEmpty()) {
            try {
                template.setLeftFloors(objectMapper.writeValueAsString(dto.getLeftFloors()));
            } catch (JsonProcessingException e) {
                log.error("左门层数据序列化失败", e);
                throw new BusinessException(500, "左门层数据格式错误");
            }
        }

        // 序列化右门层数据
        if (dto.getRightFloors() != null && !dto.getRightFloors().isEmpty()) {
            try {
                template.setRightFloors(objectMapper.writeValueAsString(dto.getRightFloors()));
            } catch (JsonProcessingException e) {
                log.error("右门层数据序列化失败", e);
                throw new BusinessException(500, "右门层数据格式错误");
            }
        }

        return template;
    }

    /**
     * 填充展示字段
     * 参考ProductServiceImpl.fillProductLabels模式
     * 为前端展示提供友好的标签和格式化数据
     *
     * @param template 层模版实体
     */
    private void fillLabels(LayerTemplate template) {
        // 1. 同步状态标签和颜色
        if (template.getSyncStatus() != null) {
            var statusLabel = EntityLabelUtils.getStatusLabel("sync", template.getSyncStatus());
            template.setSyncStatusLabel(statusLabel.getLabel());
            template.setSyncStatusColor(statusLabel.getColor());
            template.setStatusText(statusLabel.getLabel()); // 兼容性字段
        }

        // 2. 设备类型名称
        if (template.getDeviceType() != null) {
            template.setDeviceTypeName(getDeviceTypeName(template.getDeviceType()));
        }

        // 2.5. 模版类型标签
        if (template.getTemplateType() != null) {
            template.setTemplateTypeLabel(SyncConstants.getTemplateTypeDesc(template.getTemplateType()));
        }

        // 3. 左门层数据展示（美化JSON显示）
        if (template.getLeftFloors() != null && !template.getLeftFloors().isEmpty()) {
            template.setLeftFloorsDisplay(formatJsonForDisplay(template.getLeftFloors()));
        }

        // 4. 右门层数据展示
        if (template.getRightFloors() != null && !template.getRightFloors().isEmpty()) {
            template.setRightFloorsDisplay(formatJsonForDisplay(template.getRightFloors()));
        }

        // 5. 计算总层数（左门+右门）
        Integer totalFloors = calculateTotalFloors(template);
        template.setTotalFloors(totalFloors);

        // 6. 最后同步时间格式化
        if (template.getSyncTime() != null) {
            template.setLastSyncTime(formatDateTime(template.getSyncTime()));
        }

        // 7. 商品规则展示
        if (template.getGoodsRule() != null && !template.getGoodsRule().isEmpty()) {
            template.setGoodsRuleDisplay(formatJsonForDisplay(template.getGoodsRule()));
        }

        // 8. 设备名称（从 Device 表查询）
        if (template.getDeviceId() != null && !template.getDeviceId().isEmpty()) {
            try {
                Device device = deviceMapper.selectByDeviceId(template.getDeviceId());
                template.setDeviceName(device != null ? device.getName() : null);
            } catch (Exception e) {
                log.debug("查询设备名称失败: deviceId={}", template.getDeviceId(), e);
            }
        }
    }

    /**
     * 更新同步状态
     * 统一的状态更新方法，确保原子性操作
     *
     * @param deviceId   设备ID
     * @param status     新的同步状态
     * @param syncTime   同步时间（可为null）
     */
    private void updateSyncStatus(String deviceId, Integer status, LocalDateTime syncTime) {
        LambdaUpdateWrapper<LayerTemplate> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(LayerTemplate::getDeviceId, deviceId)
                     .set(LayerTemplate::getSyncStatus, status)
                     .set(LayerTemplate::getUpdateTime, LocalDateTime.now());

        if (syncTime != null) {
            updateWrapper.set(LayerTemplate::getSyncTime, syncTime);
        }

        this.update(updateWrapper);
        
        log.debug("同步状态更新: deviceId={}, status={}", deviceId,
                SyncConstants.getStatusDesc(status));
    }

    /**
     * 获取设备类型名称
     *
     * @param deviceType 设备类型代码
     * @return 设备类型名称
     */
    private String getDeviceTypeName(Integer deviceType) {
        if (deviceType == null) {
            return "未知";
        }
        return switch (deviceType) {
            case 1 -> "静态柜";
            case 2 -> "动态柜";
            case 3 -> "全部柜";
            default -> "未知类型(" + deviceType + ")";
        };
    }

    /**
     * 计算总层数
     * 从左右门的JSON数据中解析出实际层数
     *
     * @param template 层模版
     * @return 总层数
     */
    private Integer calculateTotalFloors(LayerTemplate template) {
        int leftFloors = parseFloorCount(template.getLeftFloors());
        int rightFloors = parseFloorCount(template.getRightFloors());
        return leftFloors + rightFloors;
    }

    /**
     * 从JSON字符串中解析层数量
     *
     * @param floorsJson JSON格式的层数据
     * @return 层数量
     */
    private int parseFloorCount(String floorsJson) {
        if (floorsJson == null || floorsJson.isEmpty()) {
            return 0;
        }
        try {
            List<FloorConfig> floors = objectMapper.readValue(floorsJson, 
                    new TypeReference<List<FloorConfig>>() {});
            return floors.size();
        } catch (JsonProcessingException e) {
            log.debug("解析层数失败，返回0", e);
            return 0;
        }
    }

    /**
     * 格式化JSON用于展示（美化输出）
     *
     * @param jsonStr JSON字符串
     * @return 美化后的JSON字符串
     */
    private String formatJsonForDisplay(String jsonStr) {
        try {
            Object json = objectMapper.readValue(jsonStr, Object.class);
            return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);
        } catch (JsonProcessingException e) {
            log.debug("JSON格式化失败，返回原始值", e);
            return jsonStr;
        }
    }

    /**
     * 格式化日期时间
     *
     * @param dateTime 日期时间
     * @return 格式化后的字符串
     */
    private String formatDateTime(LocalDateTime dateTime) {
        if (dateTime == null) {
            return "";
        }
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 格式化耗时显示
     *
     * @param costTimeMs 耗时（毫秒）
     * @return 可读的时间字符串
     */
    private String formatCostTime(long costTimeMs) {
        if (costTimeMs < 1000) {
            return costTimeMs + "ms";
        } else if (costTimeMs < 60000) {
            return String.format("%.2fs", costTimeMs / 1000.0);
        } else {
            return String.format("%.2fmin", costTimeMs / 60000.0);
        }
    }

    /**
     * 获取设备商品配置（转换为前端格式）
     */
    @Override
    public Map<String, Object> getProductConfig(String deviceId) {
        log.info("获取设备商品配置: deviceId={}", deviceId);

        LayerTemplate template = getByDeviceId(deviceId);
        List<Map<String, Object>> floors = new ArrayList<>();

        if (template != null && template.getLeftFloors() != null && !template.getLeftFloors().isEmpty()) {
            try {
                List<FloorConfig> leftFloors = objectMapper.readValue(
                        template.getLeftFloors(), new TypeReference<List<FloorConfig>>() {});

                int totalFloors = template.getShelfNum() != null ? template.getShelfNum() : leftFloors.size();

                for (FloorConfig config : leftFloors) {
                    int floorNum = config.getFloor() != null ? config.getFloor() : 1;
                    Map<String, Object> floor = new HashMap<>();
                    floor.put("floorNumber", floorNum);
                    floor.put("floorLabel", buildFloorLabel(floorNum, totalFloors));
                    floor.put("floorName", "第" + floorNum + "层");

                    List<Map<String, Object>> slots = new ArrayList<>();
                    List<GoodsItem> goods = config.getGoods();
                    if (goods != null) {
                        for (int i = 0; i < goods.size(); i++) {
                            GoodsItem item = goods.get(i);
                            Map<String, Object> slot = new HashMap<>();
                            slot.put("slotId", floorNum + "-" + (i + 1));
                            if (item != null && item.getKey() != null && !item.getKey().isEmpty()) {
                                slot.put("productId", item.getKey());
                                slot.put("productName", item.getLabel());
                                slot.put("productImage", normalizeImageUrl(item.getPic()));
                                slot.put("stock", item.getStock() != null ? item.getStock() : 0);
                                if (item.getC_price() != null && !item.getC_price().isEmpty()) {
                                    slot.put("price", new BigDecimal(item.getC_price()).doubleValue());
                                }
                            }
                            slots.add(slot);
                        }
                    }
                    floor.put("slots", slots);
                    floors.add(floor);
                }
            } catch (Exception e) {
                log.error("解析层数据失败, deviceId={}", deviceId, e);
            }
        }

        Map<String, Object> result = new HashMap<>();
        result.put("deviceId", deviceId);
        result.put("floors", floors);
        return result;
    }

    @Override
    public Map<String, Object> getDeviceProducts(String deviceId) {
        log.info("获取设备商品陈列信息: deviceId={}", deviceId);

        LayerTemplate template = getByDeviceId(deviceId);
        if (template == null) {
            return null;
        }

        Map<String, Object> result = new HashMap<>();
        result.put("templateName", template.getTemplateName());
        result.put("deviceId", template.getDeviceId());
        result.put("shelfNum", template.getShelfNum());
        result.put("deviceType", template.getDeviceType());

        // 解析左门层数据
        if (template.getLeftFloors() != null && !template.getLeftFloors().isEmpty()) {
            try {
                List<FloorConfig> leftFloors = objectMapper.readValue(
                    template.getLeftFloors(), new TypeReference<List<FloorConfig>>() {});
                result.put("leftFloors", leftFloors);
            } catch (Exception e) {
                log.warn("解析左门层数据失败, deviceId={}", deviceId, e);
                result.put("leftFloors", List.of());
            }
        } else {
            result.put("leftFloors", List.of());
        }

        // 解析右门层数据
        if (template.getRightFloors() != null && !template.getRightFloors().isEmpty()) {
            try {
                List<FloorConfig> rightFloors = objectMapper.readValue(
                    template.getRightFloors(), new TypeReference<List<FloorConfig>>() {});
                result.put("rightFloors", rightFloors);
            } catch (Exception e) {
                log.warn("解析右门层数据失败, deviceId={}", deviceId, e);
                result.put("rightFloors", List.of());
            }
        } else {
            result.put("rightFloors", List.of());
        }

        return result;
    }

    /**
     * 保存设备商品配置
     */
    @Override
    public boolean saveProductConfig(String deviceId, List<Map<String, Object>> floors) {
        log.info("保存设备商品配置: deviceId={}, floors.size={}", deviceId, floors != null ? floors.size() : 0);

        LayerTemplate template = getByDeviceId(deviceId);
        if (template == null) {
            throw new BusinessException(404, "设备未配置层模板，无法保存");
        }

        if (floors == null || floors.isEmpty()) {
            throw new BusinessException(400, "楼层数据不能为空");
        }

        List<FloorConfig> leftFloors = new ArrayList<>();
        for (Map<String, Object> floor : floors) {
            FloorConfig config = new FloorConfig();
            Object floorNumber = floor.get("floorNumber");
            config.setFloor(floorNumber instanceof Number ? ((Number) floorNumber).intValue() : 1);

            @SuppressWarnings("unchecked")
            List<Map<String, Object>> slots = (List<Map<String, Object>>) floor.get("slots");
            List<GoodsItem> goods = new ArrayList<>();

            if (slots != null) {
                for (Map<String, Object> slot : slots) {
                    GoodsItem item = new GoodsItem();
                    String productId = (String) slot.get("productId");
                    if (productId != null && !productId.isEmpty()) {
                        item.setKey(productId);
                        item.setLabel((String) slot.get("productName"));
                        item.setPic((String) slot.get("productImage"));
                        Object stock = slot.get("stock");
                        item.setStock(stock instanceof Number ? ((Number) stock).intValue() : 0);
                        Object price = slot.get("price");
                        if (price instanceof Number) {
                            item.setC_price(price.toString());
                        }
                    }
                    goods.add(item);
                }
            }
            config.setGoods(goods);
            leftFloors.add(config);
        }

        LayerTemplateUpdateDTO dto = new LayerTemplateUpdateDTO();
        dto.setLeftFloors(leftFloors);

        update(template.getId(), dto);

        // 推送模版到哈哈平台（根据模版类型路由到不同API）
        pushTemplateToHaha(deviceId, leftFloors);
        return true;
    }

    /**
     * 推送模版配置到哈哈平台
     * 根据设备的模版类型自动选择对应API:
     * - LAYER层模版: 使用 4.5.2 (postLayerTypeInfo)
     * - CABINET柜模版: 使用 4.5 (systemtemplate/deviceGoods)
     */
    private void pushTemplateToHaha(String deviceId, List<FloorConfig> leftFloors) {
        try {
            LayerTemplate template = getByDeviceId(deviceId);
            if (template != null && SyncConstants.TEMPLATE_TYPE_CABINET.equals(template.getTemplateType())) {
                // 柜模版: 提取所有商品编码，使用 4.5 API 覆盖更新
                String goodsCodes = extractProductCodesFromFloors(leftFloors);
                hahaClient.getGoodsApi().updateCabinetTemplate(deviceId, goodsCodes, "COVER");
                log.info("柜模版已同步到哈哈平台 - deviceId: {}, goodsCodes: {}", deviceId, goodsCodes);
            } else {
                // 层模版: 使用 4.5.2 API — 原有逻辑
                Map<String, Object> products = new HashMap<>();
                products.put("left", leftFloors);
                products.put("right", List.of());
                String productsJson = objectMapper.writeValueAsString(products);
                hahaClient.getGoodsApi().updateLayerTemplate(deviceId, productsJson);
                log.info("层模版已同步到哈哈平台 - deviceId: {}", deviceId);
            }
            updateSyncStatus(deviceId, SyncConstants.STATUS_SYNCED, LocalDateTime.now());
        } catch (Exception e) {
            log.error("推送模版到哈哈平台失败 - deviceId: {}, error: {}", deviceId, e.getMessage(), e);
        }
    }

    /**
     * 构建楼层标签（顶层/底层标识）
     */
    private String buildFloorLabel(int floorNum, int totalFloors) {
        String label = "第" + floorNum + "层";
        if (floorNum == 1) {
            label += "\n(顶层)";
        } else if (floorNum == totalFloors) {
            label += "\n(底层)";
        }
        return label;
    }

    /**
     * 标准化图片URL
     * 如果图片链接已经是完整的URL(包含http://或https://),则保持不变
     * 否则添加配置的图片域名前缀
     */
    private static final String IMAGE_DOMAIN_PREFIX = "https://img.hahabianli.com/";

    private String normalizeImageUrl(String picUrl) {
        if (picUrl == null || picUrl.isEmpty()) {
            return picUrl;
        }
        if (picUrl.startsWith("http://") || picUrl.startsWith("https://")) {
            return picUrl;
        }
        return IMAGE_DOMAIN_PREFIX + picUrl;
    }

    /**
     * 从模版API数据中提取商品编码，为不存在的商品创建库存记录（stock=0）
     * 支持层模版(4.5.1)和柜模版(4.1)两种数据格式
     * 仅在库存记录不存在时创建，已存在的记录不受影响
     */
    private void initInventoryFromTemplate(String deviceId, Map<String, Object> apiData) {
        // 提取所有商品编码
        java.util.Set<String> productCodes = new java.util.HashSet<>();

        // 层模版格式: products.left / products.right（必须 instanceof Map，柜模版可能返回 products:""）
        if (apiData.containsKey("products") && apiData.get("products") instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> products = (Map<String, Object>) apiData.get("products");
            extractCodesFromFloors(products.get("left"), productCodes);
            extractCodesFromFloors(products.get("right"), productCodes);
        }
        // 柜模版格式: dataInfo[].goods[].code
        else if (apiData.containsKey("dataInfo")) {
            @SuppressWarnings("unchecked")
            List<Map<String, Object>> dataInfoList = (List<Map<String, Object>>) apiData.get("dataInfo");
            if (dataInfoList != null) {
                for (Map<String, Object> category : dataInfoList) {
                    @SuppressWarnings("unchecked")
                    List<Map<String, Object>> goods = (List<Map<String, Object>>) category.get("goods");
                    if (goods != null) {
                        for (Map<String, Object> item : goods) {
                            Object code = item.get("code");
                            if (code != null && !code.toString().isEmpty()) {
                                productCodes.add(code.toString());
                            }
                        }
                    }
                }
            }
        }

        if (productCodes.isEmpty()) {
            log.info("设备模版中无商品配置，跳过库存初始化: deviceId={}", deviceId);
            return;
        }

        log.info("从设备模版提取到 {} 个商品编码，开始初始化库存: deviceId={}", productCodes.size(), deviceId);

        // 1. 批量查询本地商品（1 次 SELECT）
        List<Product> localProducts = productService.listByCodes(productCodes);
        Map<String, Product> codeToProduct = new HashMap<>();
        for (Product p : localProducts) {
            codeToProduct.put(p.getCode(), p);
        }

        // 2. 批量查询已有库存记录（1 次 SELECT）
        List<DeviceInventory> existingInventories = deviceInventoryService.lambdaQuery()
                .eq(DeviceInventory::getDeviceId, deviceId)
                .list();
        java.util.Set<Long> existingProductIds = new java.util.HashSet<>();
        for (DeviceInventory inv : existingInventories) {
            if (inv.getProductId() != null) {
                existingProductIds.add(inv.getProductId());
            }
        }

        // 3. 收集需要新建的库存记录
        List<DeviceInventory> newInventories = new ArrayList<>();
        int skipped = 0;

        for (String code : productCodes) {
            Product product = codeToProduct.get(code);
            if (product == null) {
                log.debug("商品编码在本地库中不存在，跳过: code={}, deviceId={}", code, deviceId);
                skipped++;
                continue;
            }
            if (existingProductIds.contains(product.getId())) {
                log.debug("库存记录已存在，跳过: deviceId={}, productCode={}", deviceId, code);
                skipped++;
                continue;
            }

            DeviceInventory inventory = new DeviceInventory();
            inventory.setDeviceId(deviceId);
            inventory.setProductId(product.getId());
            inventory.setProductCode(code);
            inventory.setProductName(product.getName());
            inventory.setStock(0);
            inventory.setWarningThreshold(5);
            inventory.setCreateTime(LocalDateTime.now());
            inventory.setUpdateTime(LocalDateTime.now());
            newInventories.add(inventory);
        }

        // 4. 批量插入（1 次批量 INSERT）
        int created = 0;
        if (!newInventories.isEmpty()) {
            deviceInventoryService.saveBatch(newInventories);
            created = newInventories.size();
            log.info("批量初始化库存记录: deviceId={}, 创建={}", deviceId, created);
        }

        log.info("库存初始化完成: deviceId={}, 创建={}, 跳过={}", deviceId, created, skipped);
    }

    /**
     * 从层数据（left/right floors）中提取商品编码
     */
    private void extractCodesFromFloors(Object floorsObj, java.util.Set<String> codeSet) {
        if (floorsObj == null) return;

        try {
            List<FloorConfig> floors = objectMapper.convertValue(floorsObj,
                    new TypeReference<List<FloorConfig>>() {});

            if (floors != null) {
                for (FloorConfig floor : floors) {
                    if (floor.getGoods() != null) {
                        for (GoodsItem goods : floor.getGoods()) {
                            if (goods.getKey() != null && !goods.getKey().isEmpty()) {
                                codeSet.add(goods.getKey());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.warn("解析层商品数据失败: {}", e.getMessage());
        }
    }

    /**
     * 从 FloorConfig 列表中提取所有商品编码，用逗号拼接
     * 用于柜模版更新时传递给 4.5 API
     */
    private String extractProductCodesFromFloors(List<FloorConfig> floors) {
        java.util.Set<String> codes = new java.util.LinkedHashSet<>();
        if (floors != null) {
            for (FloorConfig floor : floors) {
                if (floor.getGoods() != null) {
                    for (GoodsItem goods : floor.getGoods()) {
                        if (goods.getKey() != null && !goods.getKey().isEmpty()) {
                            codes.add(goods.getKey());
                        }
                    }
                }
            }
        }
        return String.join(",", codes);
    }
}
