/*
 * 文 件 名:  ChargingDeviceMappingCache
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2026/1/9
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.charging.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.ems.domain.EmsObjAttrValue;
import com.ruoyi.ems.service.IEmsObjAttrValueService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 充电桩设备映射缓存
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2026/1/9]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Component
public class ChargingDeviceMappingCache {

    private static final Logger log = LoggerFactory.getLogger(ChargingDeviceMappingCache.class);

    @Autowired
    private IEmsObjAttrValueService objAttrValueService;

    /**
     * 主机映射: pileCode -> 主机设备信息
     */
    private final Map<String, HostDeviceMapping> hostMappings = new ConcurrentHashMap<>();

    /**
     * 枪映射: fullGunNo(pileCode+gunNo) -> 枪设备信息
     */
    private final Map<String, GunDeviceMapping> gunMappings = new ConcurrentHashMap<>();

    /**
     * 反向映射: 系统设备编码 -> 协议编码
     */
    private final Map<String, String> deviceCodeToPileCode = new ConcurrentHashMap<>();

    /**
     * 主机设备映射信息
     */
    @Data
    public static class HostDeviceMapping {
        /**
         * 协议层桩编码 (14位)
         */
        private String pileCode;

        /**
         * 系统设备编码
         */
        private String deviceCode;

        /**
         * 设备名称
         */
        private String deviceName;

        /**
         * 枪数量
         */
        private int gunCount;

        /**
         * 子设备列表
         */
        private List<String> subDeviceCodes;

        /**
         * 创建时间
         */
        private LocalDateTime createTime;
    }

    /**
     * 枪设备映射信息
     */
    @Data
    public static class GunDeviceMapping {
        /**
         * 协议层桩编码 (14位)
         */
        private String pileCode;

        /**
         * 协议层枪号 (2位)
         */
        private String gunNo;

        /**
         * 完整枪号 (16位)
         */
        private String fullGunNo;

        /**
         * 系统设备编码
         */
        private String deviceCode;

        /**
         * 设备名称
         */
        private String deviceName;

        /**
         * 所属主机设备编码
         */
        private String hostDeviceCode;

        /**
         * 创建时间
         */
        private LocalDateTime createTime;
    }

    /**
     * 初始化缓存 - 启动时加载
     */
    @PostConstruct
    public void initCache() {
        log.info("开始初始化充电桩设备映射缓存...");

        try {
            // 1. 加载所有主机设备
            List<EmsObjAttrValue> hostPileCodes = objAttrValueService.selectByAttrKey("M_W2_DEV_CHARGING_HOST",
                "pileCode");

            for (EmsObjAttrValue attr : hostPileCodes) {
                String deviceCode = attr.getObjCode();
                String pileCode = attr.getAttrValue();

                if (StringUtils.isBlank(pileCode)) {
                    continue;
                }

                // 查询其他属性
                EmsObjAttrValue gunCountAttr = objAttrValueService.selectObjAttrValue("M_W2_DEV_CHARGING_HOST",
                    deviceCode, "gunCount");
                EmsObjAttrValue subDevAttr = objAttrValueService.selectObjAttrValue("M_W2_DEV_CHARGING_HOST",
                    deviceCode, "subDev");

                HostDeviceMapping mapping = new HostDeviceMapping();
                mapping.setPileCode(pileCode);
                mapping.setDeviceCode(deviceCode);
                mapping.setGunCount(gunCountAttr != null ? Integer.parseInt(gunCountAttr.getAttrValue()) : 0);
                mapping.setCreateTime(LocalDateTime.now());

                // 解析子设备列表
                if (subDevAttr != null && StringUtils.isNotBlank(subDevAttr.getAttrValue())) {
                    JSONArray subDevArray = JSON.parseArray(subDevAttr.getAttrValue());
                    List<String> subDeviceCodes = new ArrayList<>();
                    for (int i = 0; i < subDevArray.size(); i++) {
                        JSONObject subDev = subDevArray.getJSONObject(i);
                        subDeviceCodes.add(subDev.getString("deviceCode"));
                    }
                    mapping.setSubDeviceCodes(subDeviceCodes);
                }

                hostMappings.put(pileCode, mapping);
                deviceCodeToPileCode.put(deviceCode, pileCode);

                log.debug("加载主机映射: {} -> {}", pileCode, deviceCode);
            }

            // 2. 加载所有枪设备
            List<EmsObjAttrValue> gunPileCodes = objAttrValueService.selectByAttrKey("M_W2_DEV_CHARGING_PILE",
                "pileCode");

            for (EmsObjAttrValue attr : gunPileCodes) {
                String deviceCode = attr.getObjCode();
                String pileCode = attr.getAttrValue();

                if (StringUtils.isBlank(pileCode)) {
                    continue;
                }

                // 查询枪号
                EmsObjAttrValue gunNoAttr = objAttrValueService.selectObjAttrValue("M_W2_DEV_CHARGING_PILE", deviceCode,
                    "gunNo");

                if (gunNoAttr == null || StringUtils.isBlank(gunNoAttr.getAttrValue())) {
                    log.warn("充电枪 {} 缺少枪号属性", deviceCode);
                    continue;
                }

                String gunNo = gunNoAttr.getAttrValue();
                String fullGunNo = pileCode + gunNo;

                GunDeviceMapping mapping = new GunDeviceMapping();
                mapping.setPileCode(pileCode);
                mapping.setGunNo(gunNo);
                mapping.setFullGunNo(fullGunNo);
                mapping.setDeviceCode(deviceCode);
                mapping.setCreateTime(LocalDateTime.now());

                // 关联主机
                HostDeviceMapping hostMapping = hostMappings.get(pileCode);
                if (hostMapping != null) {
                    mapping.setHostDeviceCode(hostMapping.getDeviceCode());
                }

                gunMappings.put(fullGunNo, mapping);
                deviceCodeToPileCode.put(deviceCode, fullGunNo);

                log.debug("加载枪映射: {} -> {}", fullGunNo, deviceCode);
            }

            log.info("充电桩设备映射缓存初始化完成 - 主机: {}个, 枪: {}个", hostMappings.size(), gunMappings.size());

        }
        catch (Exception e) {
            log.error("初始化充电桩设备映射缓存失败", e);
        }
    }

    /**
     * 根据桩编码获取主机设备编码
     */
    public String getHostDeviceCode(String pileCode) {
        HostDeviceMapping mapping = hostMappings.get(pileCode);
        return mapping != null ? mapping.getDeviceCode() : null;
    }

    /**
     * 根据完整枪号获取枪设备编码
     */
    public String getGunDeviceCode(String fullGunNo) {
        GunDeviceMapping mapping = gunMappings.get(fullGunNo);
        return mapping != null ? mapping.getDeviceCode() : null;
    }

    /**
     * 根据桩编码和枪号获取枪设备编码
     */
    public String getGunDeviceCode(String pileCode, String gunNo) {
        return getGunDeviceCode(pileCode + gunNo);
    }

    /**
     * 根据设备编码获取协议编码
     */
    public String getProtocolCode(String deviceCode) {
        return deviceCodeToPileCode.get(deviceCode);
    }

    /**
     * 获取主机映射信息
     */
    public HostDeviceMapping getHostMapping(String pileCode) {
        return hostMappings.get(pileCode);
    }

    /**
     * 获取枪映射信息
     */
    public GunDeviceMapping getGunMapping(String fullGunNo) {
        return gunMappings.get(fullGunNo);
    }

    /**
     * 获取枪映射信息
     */
    public GunDeviceMapping getGunMapping(String pileCode, String gunNo) {
        return gunMappings.get(pileCode + gunNo);
    }

    /**
     * 清除缓存
     */
    public void clearCache() {
        hostMappings.clear();
        gunMappings.clear();
        deviceCodeToPileCode.clear();
        log.info("充电桩设备映射缓存已清除");
    }

    /**
     * 刷新缓存
     */
    public void refreshCache() {
        clearCache();
        initCache();
    }

    /**
     * 获取缓存统计信息
     */
    public Map<String, Object> getCacheStats() {
        Map<String, Object> stats = new HashMap<>();
        stats.put("hostMappings", hostMappings.size());
        stats.put("gunMappings", gunMappings.size());
        stats.put("deviceCodeMappings", deviceCodeToPileCode.size());
        return stats;
    }
}