/*
 * 文 件 名:  MockPileClientManager
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  Mock充电桩客户端管理器
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/23
 */
package com.ruoyi.ems.charging.mock.simulator;

import com.ruoyi.ems.charging.mock.config.MockPileConfig;
import com.ruoyi.ems.charging.mock.config.MockPileConfig.PileHostConfig;
import com.ruoyi.ems.charging.mock.model.MockGunState;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Mock充电桩客户端管理器
 * 管理多个Mock充电桩客户端实例
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/23]
 */
public class MockPileClientManager {

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

    /**
     * 配置
     */
    private final MockPileConfig config;

    /**
     * 客户端映射 - 桩编号 -> 客户端
     */
    private final Map<String, MockPileClient> clientMap = new ConcurrentHashMap<>();

    /**
     * 共享的事件循环组
     */
    private EventLoopGroup sharedEventLoopGroup;

    /**
     * 是否已启动
     */
    private volatile boolean started = false;

    /**
     * 构造函数
     *
     * @param config 配置
     */
    public MockPileClientManager(MockPileConfig config) {
        this.config = config;
    }

    /**
     * 启动所有客户端
     */
    public synchronized void startAll() {
        if (started) {
            log.warn("Mock充电桩客户端管理器已启动");
            return;
        }

        log.info("启动Mock充电桩客户端管理器...");
        log.info("服务器地址: {}:{}", config.getServerHost(), config.getServerPort());
        log.info("充电桩主机数量: {}", config.getPileHosts().size());

        // 创建共享的事件循环组
        int workerThreads = Math.min(config.getPileHosts().size(), 4);
        sharedEventLoopGroup = new NioEventLoopGroup(workerThreads);

        // 创建并启动所有客户端
        for (PileHostConfig hostConfig : config.getPileHosts()) {
            MockPileClient client = new MockPileClient(hostConfig, config, sharedEventLoopGroup);
            clientMap.put(hostConfig.getPileCode(), client);
            client.start();

            log.info("创建客户端: pileCode={}, gunCount={}, desc={}",
                    hostConfig.getPileCode(), hostConfig.getGunCount(), hostConfig.getDescription());
        }

        started = true;
        log.info("Mock充电桩客户端管理器启动完成, 共{}个客户端", clientMap.size());
    }

    /**
     * 停止所有客户端
     */
    public synchronized void stopAll() {
        if (!started) {
            return;
        }

        log.info("停止Mock充电桩客户端管理器...");

        // 停止所有客户端
        for (MockPileClient client : clientMap.values()) {
            try {
                client.stop();
            } catch (Exception e) {
                log.error("停止客户端[{}]失败", client.getPileCode(), e);
            }
        }

        clientMap.clear();

        // 关闭事件循环组
        if (sharedEventLoopGroup != null) {
            sharedEventLoopGroup.shutdownGracefully();
            sharedEventLoopGroup = null;
        }

        started = false;
        log.info("Mock充电桩客户端管理器已停止");
    }

    /**
     * 获取指定客户端
     *
     * @param pileCode 桩编号
     * @return 客户端
     */
    public MockPileClient getClient(String pileCode) {
        return clientMap.get(pileCode);
    }

    /**
     * 获取所有客户端
     *
     * @return 客户端集合
     */
    public Collection<MockPileClient> getAllClients() {
        return clientMap.values();
    }

    /**
     * 获取所有枪的状态
     *
     * @return 枪状态列表
     */
    public List<MockGunState> getAllGunStates() {
        List<MockGunState> allStates = new ArrayList<>();
        for (MockPileClient client : clientMap.values()) {
            allStates.addAll(client.getAllGunStates());
        }
        return allStates;
    }

    /**
     * 获取指定枪的状态
     *
     * @param pileCode 桩编号
     * @param gunNo    枪号
     * @return 枪状态
     */
    public MockGunState getGunState(String pileCode, String gunNo) {
        MockPileClient client = clientMap.get(pileCode);
        if (client != null) {
            return client.getGunState(gunNo);
        }
        return null;
    }

    /**
     * 手动开始充电
     *
     * @param pileCode 桩编号
     * @param gunNo    枪号
     */
    public void startCharging(String pileCode, String gunNo) {
        MockPileClient client = clientMap.get(pileCode);
        if (client != null) {
            client.startCharging(gunNo);
        } else {
            log.warn("未找到桩编号: {}", pileCode);
        }
    }

    /**
     * 手动停止充电
     *
     * @param pileCode 桩编号
     * @param gunNo    枪号
     */
    public void stopCharging(String pileCode, String gunNo) {
        MockPileClient client = clientMap.get(pileCode);
        if (client != null) {
            client.stopCharging(gunNo);
        } else {
            log.warn("未找到桩编号: {}", pileCode);
        }
    }

    /**
     * 获取状态统计
     *
     * @return 状态统计信息
     */
    public Map<String, Object> getStatistics() {
        Map<String, Object> stats = new LinkedHashMap<>();

        int totalClients = clientMap.size();
        int connectedClients = 0;
        int loggedInClients = 0;
        int totalGuns = 0;
        int chargingGuns = 0;
        int idleGuns = 0;
        double totalPower = 0;
        double totalEnergy = 0;

        for (MockPileClient client : clientMap.values()) {
            if (client.isConnected()) {
                connectedClients++;
            }
            if (client.isLoggedIn()) {
                loggedInClients++;
            }

            for (MockGunState gunState : client.getAllGunStates()) {
                totalGuns++;
                if (gunState.isCharging()) {
                    chargingGuns++;
                    totalPower += gunState.getOutputPower();
                    totalEnergy += gunState.getChargingEnergy();
                } else if (gunState.isIdle()) {
                    idleGuns++;
                }
            }
        }

        stats.put("totalClients", totalClients);
        stats.put("connectedClients", connectedClients);
        stats.put("loggedInClients", loggedInClients);
        stats.put("totalGuns", totalGuns);
        stats.put("chargingGuns", chargingGuns);
        stats.put("idleGuns", idleGuns);
        stats.put("totalPowerKw", String.format("%.2f", totalPower));
        stats.put("totalEnergyKwh", String.format("%.4f", totalEnergy));

        return stats;
    }

    /**
     * 打印状态
     */
    public void printStatus() {
        Map<String, Object> stats = getStatistics();

        log.info("========== Mock充电桩状态 ==========");
        log.info("客户端: 总数={}, 已连接={}, 已登录={}",
                stats.get("totalClients"),
                stats.get("connectedClients"),
                stats.get("loggedInClients"));
        log.info("充电枪: 总数={}, 充电中={}, 空闲={}",
                stats.get("totalGuns"),
                stats.get("chargingGuns"),
                stats.get("idleGuns"));
        log.info("当前功率: {}kW, 累计电量: {}kWh",
                stats.get("totalPowerKw"),
                stats.get("totalEnergyKwh"));
        log.info("====================================");

        // 打印每个客户端的详细状态
        for (MockPileClient client : clientMap.values()) {
            StringBuilder sb = new StringBuilder();
            sb.append(String.format("[%s] connected=%s, loggedIn=%s | ",
                    client.getPileCode(),
                    client.isConnected(),
                    client.isLoggedIn()));

            for (MockGunState gunState : client.getAllGunStates()) {
                sb.append(String.format("gun%s:%s(%.1fkW) ",
                        gunState.getGunNo(),
                        gunState.isCharging() ? "充电" : "空闲",
                        gunState.getOutputPower()));
            }

            log.info(sb.toString());
        }
    }

    /**
     * 是否已启动
     */
    public boolean isStarted() {
        return started;
    }

    /**
     * 获取配置
     */
    public MockPileConfig getConfig() {
        return config;
    }
}
