/*
 * 文 件 名:  ChargingHandler
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  充电桩适配处理Handler
 * 修 改 人:  lvwenbin
 * 修改时间:  2026/1/9
 */
package com.ruoyi.ems.charging.handler;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.ems.charging.service.ChargingDeviceMappingCache;
import com.ruoyi.ems.charging.core.ChargingPileSessionManager;
import com.ruoyi.ems.charging.service.ChargingDataService;
import com.ruoyi.ems.charging.service.PowerControlService;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.domain.EmsObjAttrValue;
import com.ruoyi.ems.enums.DevObjType;
import com.ruoyi.ems.enums.DevOnlineStatus;
import com.ruoyi.ems.handle.BaseDevHandler;
import com.ruoyi.ems.model.AbilityPayload;
import com.ruoyi.ems.model.CallResponse;
import com.ruoyi.ems.model.QueryDevice;
import org.apache.commons.collections4.CollectionUtils;
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.Service;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 充电桩适配处理Handler
 * 处理充电桩系统、主机、充电枪的能力调用
 *
 * @author lvwenbin
 * @version [版本号, 2026/1/9]
 */
@Service("chargingHandler")
public class ChargingHandler extends BaseDevHandler {

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

    /**
     * 充电系统模型代码
     */
    private static final String MODEL_CODE_SYS = "M_W2_SYS_CHARGING";

    /**
     * 充电主机模型代码
     */
    private static final String MODEL_CODE_HOST = "M_W2_DEV_CHARGING_HOST";

    /**
     * 充电枪模型代码
     */
    private static final String MODEL_CODE_PILE = "M_W2_DEV_CHARGING_PILE";

    /**
     * 子系统代码
     */
    private static final String SUBSYSTEM_CODE = "SYS_CD";

    @Autowired
    private PowerControlService powerControlService;

    @Autowired
    private ChargingDataService chargingDataService;

    @Autowired
    private ChargingPileSessionManager sessionManager;

    @Autowired
    private ChargingDeviceMappingCache deviceMappingCache;

    @Override
    public CallResponse<Void> call(AbilityPayload abilityParam) {
        CallResponse<Void> callResponse;

        try {
            log.info("充电桩能力调用: {}", abilityParam);

            int objType = abilityParam.getObjType();
            String modelCode = abilityParam.getModelCode();
            String abilityKey = abilityParam.getAbilityKey();
            String objCode = abilityParam.getObjCode();
            String param = abilityParam.getAbilityParam();

            // 根据对象类型分发处理
            if (DevObjType.SYSTEM.getCode() == objType) {
                // 系统级能力
                callResponse = handleSystemAbility(abilityKey, param);
            }
            else if (DevObjType.DEVC.getCode() == objType) {
                // 设备级能力
                if (MODEL_CODE_HOST.equals(modelCode)) {
                    callResponse = handleHostAbility(objCode, abilityKey, param);
                }
                else if (MODEL_CODE_PILE.equals(modelCode)) {
                    callResponse = handlePileAbility(objCode, abilityKey, param);
                }
                else {
                    callResponse = new CallResponse<>(-1, "不支持的模型代码: " + modelCode);
                }
            }
            else {
                callResponse = new CallResponse<>(-1, "不支持的对象类型: " + objType);
            }

            // 记录调用日志
            saveCallLog(objCode, modelCode, abilityKey, callResponse.getCode() == 0 ? 0 : -1, param,
                callResponse.getMessage());

        }
        catch (Exception e) {
            log.error("充电桩能力调用异常", e);
            callResponse = new CallResponse<>(-1, "内部错误: " + e.getMessage());
        }

        return callResponse;
    }

    /**
     * 处理系统级能力
     */
    private CallResponse<Void> handleSystemAbility(String abilityKey, String param) {
        switch (abilityKey) {
            case "setAllPilesPowerLimit":
                // 批量设置功率限制
                int powerPercent = param != null ? Integer.parseInt(param) : 100;
                if (powerPercent < 30 || powerPercent > 100) {
                    return new CallResponse<>(-1, "功率百分比需在30-100之间");
                }
                powerControlService.setAllPilesPowerLimit(powerPercent);
                return new CallResponse<>(0, "批量功率限制指令已发送");

            case "stopAllCharging":
                // 全部停止充电
                int stopCount = powerControlService.stopAllCharging();
                return new CallResponse<>(0, "已发送停止充电指令: " + stopCount + "条");

            case "clearCache":
                chargingDataService.clearDeviceCodeCache();
                return new CallResponse<>(0, "设备映射缓存已刷新");

            case "getCacheStats":
                // 获取缓存统计
                return new CallResponse<>(0, JSON.toJSONString(chargingDataService.getCacheStats()));

            default:
                return new CallResponse<>(-1, "不支持的系统能力: " + abilityKey);
        }
    }

    /**
     * 处理充电主机能力
     */
    private CallResponse<Void> handleHostAbility(String objCode, String abilityKey, String param) {
        String pileCode = getPileCodeByDeviceCode(objCode);
        if (StringUtils.isBlank(pileCode)) {
            return new CallResponse<>(-1, "未找到设备的桩编码: " + objCode);
        }

        switch (abilityKey) {
            case "setMaxOutputPower":
                // 设置最大输出功率
                int powerPercent = param != null ? Integer.parseInt(param) : 100;
                if (powerPercent < 30 || powerPercent > 100) {
                    return new CallResponse<>(-1, "功率百分比需在30-100之间");
                }
                boolean powerResult = powerControlService.setMaxOutputPower(pileCode, powerPercent);
                return powerResult ?
                    new CallResponse<>(0, "功率设置指令已发送") :
                    new CallResponse<>(-1, "功率设置指令发送失败，请检查设备是否在线");

            case "enablePile":
                // 启用充电桩
                boolean enableResult = powerControlService.enablePile(pileCode);
                return enableResult ?
                    new CallResponse<>(0, "启用指令已发送") :
                    new CallResponse<>(-1, "启用指令发送失败");

            case "disablePile":
                // 禁用充电桩
                boolean disableResult = powerControlService.disablePile(pileCode);
                return disableResult ?
                    new CallResponse<>(0, "禁用指令已发送") :
                    new CallResponse<>(-1, "禁用指令发送失败");

            default:
                return new CallResponse<>(-1, "不支持的主机能力: " + abilityKey);
        }
    }

    /**
     * 处理充电枪能力
     */
    private CallResponse<Void> handlePileAbility(String objCode, String abilityKey, String param) {
        String pileCode = getGunPileCode(objCode);
        String gunNo = getGunNo(objCode);

        if (StringUtils.isBlank(pileCode) || StringUtils.isBlank(gunNo)) {
            return new CallResponse<>(-1, "未找到设备的桩编码或枪号: " + objCode);
        }

        switch (abilityKey) {
            case "remoteStop":
                // 远程停止充电
                boolean stopResult = powerControlService.remoteStop(pileCode, gunNo);
                return stopResult ?
                    new CallResponse<>(0, "远程停机指令已发送") :
                    new CallResponse<>(-1, "远程停机指令发送失败，请检查设备是否在线");

            case "readRealtimeData":
                // 主动读取实时数据
                boolean readResult = powerControlService.readRealtimeData(pileCode, gunNo);
                return readResult ?
                    new CallResponse<>(0, "读取数据指令已发送") :
                    new CallResponse<>(-1, "读取数据指令发送失败");

            default:
                return new CallResponse<>(-1, "不支持的充电枪能力: " + abilityKey);
        }
    }

    /**
     * 根据设备编码获取桩编码（充电主机）
     */
    private String getPileCodeByDeviceCode(String deviceCode) {
        String protocolCode = deviceMappingCache.getProtocolCode(deviceCode);

        // 验证是否为主机编码（14位）
        if (protocolCode != null) {
            return protocolCode;
        }

        log.warn("设备 {} 的协议编码不是有效的桩编码: {}", deviceCode, protocolCode);
        return null;
    }

    /**
     * 获取充电枪的桩编码
     */
    private String getGunPileCode(String deviceCode) {
        String fullGunNo = deviceMappingCache.getProtocolCode(deviceCode);

        // 提取桩编码（前14位）
        if (fullGunNo != null && fullGunNo.length() == 16) {
            return fullGunNo.substring(0, 14);
        }

        log.warn("设备 {} 的协议编码不是有效的完整枪号: {}", deviceCode, fullGunNo);
        return null;
    }

    /**
     * 获取充电枪的枪号
     */
    private String getGunNo(String deviceCode) {
        String fullGunNo = deviceMappingCache.getProtocolCode(deviceCode);

        // 提取枪号（后2位）
        if (fullGunNo != null && fullGunNo.length() == 16) {
            return fullGunNo.substring(14);
        }

        log.warn("设备 {} 的协议编码不是有效的完整枪号: {}", deviceCode, fullGunNo);
        return null;
    }

    @Override
    public List<EmsDevice> getDeviceList() {
        // 返回所有充电主机设备
        QueryDevice queryDevice = new QueryDevice();
        queryDevice.setDeviceModel(MODEL_CODE_HOST);
        queryDevice.setSubsystemCode(SUBSYSTEM_CODE);
        return deviceService.selectList(queryDevice);
    }

    @Override
    public void refreshOnline() {
        log.info("开始刷新充电桩在线状态...");

        try {
            // 查询本地充电主机设备
            QueryDevice queryHost = new QueryDevice();
            queryHost.setDeviceModel(MODEL_CODE_HOST);
            queryHost.setSubsystemCode(SUBSYSTEM_CODE);
            List<EmsDevice> hostDevices = deviceService.selectList(queryHost);

            for (EmsDevice device : hostDevices) {
                try {
                    String pileCode = getPileCodeByDeviceCode(device.getDeviceCode());
                    if (StringUtils.isBlank(pileCode)) {
                        continue;
                    }

                    // 通过SessionManager判断桩是否在线
                    boolean isOnline = sessionManager.isOnline(pileCode);
                    DevOnlineStatus newStatus = isOnline ? DevOnlineStatus.ONLINE : DevOnlineStatus.OFFLINE;

                    // 更新状态
                    refreshStatus(device, newStatus);

                    // 同步更新该主机下所有充电枪的状态
                    updateGunOnlineStatus(device.getDeviceCode(), isOnline);

                }
                catch (Exception e) {
                    log.error("刷新充电主机 {} 状态异常", device.getDeviceCode(), e);
                }
            }

            log.info("充电桩在线状态刷新完成");

        }
        catch (Exception e) {
            log.error("刷新充电桩在线状态异常", e);
        }
    }

    /**
     * 更新充电枪在线状态
     */
    private void updateGunOnlineStatus(String hostDeviceCode, boolean isOnline) {
        try {
            String pileCode = deviceMappingCache.getProtocolCode(hostDeviceCode);
            if (StringUtils.isBlank(pileCode)) {
                return;
            }

            ChargingDeviceMappingCache.HostDeviceMapping hostMapping =
                deviceMappingCache.getHostMapping(pileCode);

            if (hostMapping == null || CollectionUtils.isEmpty(hostMapping.getSubDeviceCodes())) {
                return;
            }

            for (String gunDeviceCode : hostMapping.getSubDeviceCodes()) {
                // 查询枪设备
                EmsDevice gunDevice = deviceService.selectByCode(gunDeviceCode);
                if (gunDevice != null) {
                    DevOnlineStatus newStatus = isOnline ? DevOnlineStatus.ONLINE : DevOnlineStatus.OFFLINE;
                    refreshStatus(gunDevice, newStatus);
                }
            }

        }
        catch (Exception e) {
            log.error("更新充电枪在线状态异常 - 主机: {}", hostDeviceCode, e);
        }
    }

    /**
     * 同步单个主机属性
     */
    public void syncHostAttr(String deviceCode) {
        log.info("同步充电主机 {} 属性", deviceCode);

        try {
            // 使用统一缓存获取桩编码
            String pileCode = getPileCodeByDeviceCode(deviceCode);
            if (StringUtils.isBlank(pileCode)) {
                log.warn("充电主机 {} 无对应桩编码", deviceCode);
                return;
            }

            // 检查桩是否在线
            if (!sessionManager.isOnline(pileCode)) {
                log.warn("充电桩 {} 不在线，无法同步属性", pileCode);
                return;
            }

            // 获取会话信息
            ChargingPileSessionManager.PileSession session = sessionManager.getSession(pileCode);
            if (session == null) {
                return;
            }

            // 获取现有属性
            List<EmsObjAttrValue> existingAttrs = objAttrValueService.selectByObjCode(MODEL_CODE_HOST, deviceCode);
            Map<String, EmsObjAttrValue> attrMap = existingAttrs.stream()
                .collect(Collectors.toMap(EmsObjAttrValue::getAttrKey, Function.identity(), (k1, k2) -> k1));

            // 更新枪数量
            checkAndUpdate(attrMap, deviceCode, MODEL_CODE_HOST, "gunCount", String.valueOf(session.getGunCount()));

            log.info("充电主机 {} 属性同步完成", deviceCode);

        }
        catch (Exception e) {
            log.error("同步充电主机 {} 属性异常", deviceCode, e);
        }
    }

    /**
     * 同步单个充电枪属性
     */
    public void syncGunAttr(String deviceCode) {
        log.info("同步充电枪 {} 属性", deviceCode);

        try {
            String pileCode = getGunPileCode(deviceCode);
            String gunNo = getGunNo(deviceCode);

            if (StringUtils.isBlank(pileCode) || StringUtils.isBlank(gunNo)) {
                log.warn("充电枪 {} 无pileCode或gunNo属性", deviceCode);
                return;
            }

            // 发送读取实时数据指令
            boolean result = powerControlService.readRealtimeData(pileCode, gunNo);
            if (result) {
                log.info("充电枪 {} 属性同步指令已发送", deviceCode);
            }
            else {
                log.warn("充电枪 {} 属性同步指令发送失败", deviceCode);
            }

        }
        catch (Exception e) {
            log.error("同步充电枪 {} 属性异常", deviceCode, e);
        }
    }
}