package com.qqchen.deploy.backend.framework.ssh.impl;

import com.qqchen.deploy.backend.framework.dto.CommandResult;
import com.qqchen.deploy.backend.framework.dto.DiskInfo;
import com.qqchen.deploy.backend.framework.dto.DiskUsageInfo;
import com.qqchen.deploy.backend.framework.dto.MonitorData;
import com.qqchen.deploy.backend.framework.enums.OsTypeEnum;
import com.qqchen.deploy.backend.framework.ssh.AbstractSSHCommandService;
import lombok.extern.slf4j.Slf4j;
import net.schmizz.sshj.SSHClient;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * Linux SSH命令服务实现（Framework层）
 */
@Slf4j
@Service
public class LinuxSSHCommandServiceImpl extends AbstractSSHCommandService {
    
    // ==================== 命令常量 ====================
    
    /**
     * CPU使用率命令
     */
    private static final String CMD_CPU_USAGE = 
        "top -bn1 | grep 'Cpu(s)' | awk '{print $2}' | sed 's/%us,//'";
    
    /**
     * 内存使用率命令
     */
    private static final String CMD_MEMORY_USAGE = 
        "free | grep Mem | awk '{printf \"%.2f\", ($2-$7)/$2 * 100}'";
    
    /**
     * 磁盘使用率命令（格式：设备|挂载点|文件系统|总容量|已用|使用率）
     */
    private static final String CMD_DISK_USAGE = 
        "df -BG -T | grep -E '^/dev/(sd|vd|nvme|mapper|xvd)' | " +
        "awk '{print $1 \"|\" $7 \"|\" $2 \"|\" $3 \"|\" $4 \"|\" $6}' | " +
        "sed 's/G//g; s/%//'";
    
    /**
     * 网络接收流量命令(KB/s)
     */
    private static final String CMD_NETWORK_RX = 
        "cat /proc/net/dev | grep -vE 'lo:|face' | awk '{sum+=$2} END {print int(sum/1024)}'";
    
    /**
     * 网络发送流量命令(KB/s)
     */
    private static final String CMD_NETWORK_TX = 
        "cat /proc/net/dev | grep -vE 'lo:|face' | awk '{sum+=$10} END {print int(sum/1024)}'";
    
    // ==================== 实现方法 ====================
    
    @Override
    public String getHostname(SSHClient sshClient) {
        return safeExecute(sshClient, "hostname");
    }
    
    @Override
    public String getOsVersion(SSHClient sshClient) {
        // 优先使用 /etc/os-release，fallback 到 lsb_release
        String command = "cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d'\"' -f2 || " +
                        "lsb_release -d 2>/dev/null | cut -f2 || " +
                        "cat /etc/issue | head -1";
        return safeExecute(sshClient, command);
    }
    
    @Override
    public Integer getCpuCores(SSHClient sshClient) {
        String result = safeExecute(sshClient, "nproc");
        return parseInteger(result);
    }
    
    @Override
    public Integer getMemorySize(SSHClient sshClient) {
        // 使用 free -g 获取GB单位的内存
        String result = safeExecute(sshClient, "free -g | grep Mem | awk '{print $2}'");
        return parseInteger(result);
    }
    
    @Override
    public List<DiskInfo> getDiskInfo(SSHClient sshClient) {
        // 使用df命令获取所有挂载点的磁盘信息
        // 格式: 设备|挂载点|文件系统类型|总大小(GB)
        // 过滤条件：只保留 /dev/sd*, /dev/vd*, /dev/nvme*, /dev/mapper/* 等真实磁盘设备
        // 排除：loop设备、tmpfs、overlay等
        String command = "df -BG -T | grep -E '^/dev/(sd|vd|nvme|mapper|xvd)' | awk '{print $1 \"|\" $7 \"|\" $2 \"|\" $3}' | sed 's/G//g'";
        String result = safeExecute(sshClient, command);
        
        List<DiskInfo> diskList = new ArrayList<>();
        Set<String> seenDevices = new HashSet<>();  // 用于去重：同一设备只记录一次
        
        if (result != null && !result.trim().isEmpty()) {
            String[] lines = result.trim().split("\\n");
            for (String line : lines) {
                String[] parts = line.split("\\|");
                if (parts.length >= 4) {
                    try {
                        String device = parts[0].trim();
                        String mountPoint = parts[1].trim();
                        String fileSystem = parts[2].trim();
                        String sizeStr = parts[3].trim();
                        
                        // 去重：如果同一个设备已经记录过，跳过（避免子卷、绑定挂载重复）
                        if (seenDevices.contains(device)) {
                            log.debug("跳过重复设备: {} -> {}", device, mountPoint);
                            continue;
                        }
                        seenDevices.add(device);
                        
                        DiskInfo diskInfo = DiskInfo.builder()
                            .mountPoint(mountPoint)
                            .fileSystem(fileSystem)
                            .totalSize(new BigDecimal(sizeStr))
                            .build();
                        diskList.add(diskInfo);
                    } catch (NumberFormatException e) {
                        log.warn("解析磁盘信息失败: {}", line, e);
                    }
                }
            }
        }
        return diskList;
    }
    
    @Override
    public BigDecimal getCpuUsage(SSHClient sshClient) {
        String result = safeExecute(sshClient, CMD_CPU_USAGE);
        return parseBigDecimal(result);
    }
    
    @Override
    public BigDecimal getMemoryUsage(SSHClient sshClient) {
        String result = safeExecute(sshClient, CMD_MEMORY_USAGE);
        return parseBigDecimal(result);
    }
    
    @Override
    public List<DiskUsageInfo> getDiskUsage(SSHClient sshClient) {
        String result = safeExecute(sshClient, CMD_DISK_USAGE);
        
        List<DiskUsageInfo> diskUsageList = new ArrayList<>();
        Set<String> seenDevices = new HashSet<>();
        
        if (result != null && !result.trim().isEmpty()) {
            String[] lines = result.trim().split("\\n");
            for (String line : lines) {
                String[] parts = line.split("\\|");
                if (parts.length >= 6) {
                    try {
                        String device = parts[0].trim();
                        String mountPoint = parts[1].trim();
                        String fileSystem = parts[2].trim();
                        String totalStr = parts[3].trim();
                        String usedStr = parts[4].trim();
                        String usageStr = parts[5].trim();
                        
                        // 去重
                        if (seenDevices.contains(device)) {
                            continue;
                        }
                        seenDevices.add(device);
                        
                        DiskUsageInfo diskUsage = DiskUsageInfo.builder()
                            .mountPoint(mountPoint)
                            .fileSystem(fileSystem)
                            .totalSize(new BigDecimal(totalStr))
                            .usedSize(new BigDecimal(usedStr))
                            .usagePercent(new BigDecimal(usageStr))
                            .build();
                        diskUsageList.add(diskUsage);
                    } catch (NumberFormatException e) {
                        log.warn("解析磁盘使用率失败: {}", line, e);
                    }
                }
            }
        }
        return diskUsageList;
    }
    
    @Override
    public Long getNetworkRx(SSHClient sshClient) {
        String result = safeExecute(sshClient, CMD_NETWORK_RX);
        return parseLong(result);
    }
    
    @Override
    public Long getNetworkTx(SSHClient sshClient) {
        String result = safeExecute(sshClient, CMD_NETWORK_TX);
        return parseLong(result);
    }
    
    /**
     * 解析 Long 类型结果
     */
    private Long parseLong(String result) {
        if (result == null || result.trim().isEmpty()) {
            return null;
        }
        try {
            return Long.parseLong(result.trim());
        } catch (NumberFormatException e) {
            log.warn("解析Long失败: {}", result, e);
            return null;
        }
    }
    
    @Override
    public MonitorData collectMonitorData(SSHClient sshClient) {
        try {
            // 1. 准备5个监控命令（使用统一的命令常量 ✅）
            List<String> commands = Arrays.asList(
                CMD_CPU_USAGE,
                CMD_MEMORY_USAGE,
                CMD_DISK_USAGE,
                CMD_NETWORK_RX,
                CMD_NETWORK_TX
            );
            
            // 2. 批量执行命令（只需1次网络往返 ✅）
            List<CommandResult> results = executeCommands(sshClient, commands);
            
            // 3. 解析结果
            BigDecimal cpuUsage = parseCommandResultToBigDecimal(results.get(0));
            BigDecimal memoryUsage = parseCommandResultToBigDecimal(results.get(1));
            List<DiskUsageInfo> diskUsage = parseDiskUsageFromCommand(results.get(2));
            Long networkRx = parseCommandResultToLong(results.get(3));
            Long networkTx = parseCommandResultToLong(results.get(4));
            
            // 4. 构建监控数据
            return MonitorData.builder()
                .cpuUsage(cpuUsage)
                .memoryUsage(memoryUsage)
                .diskUsage(diskUsage)
                .networkRx(networkRx)
                .networkTx(networkTx)
                .build();
                
        } catch (Exception e) {
            log.error("批量采集Linux监控数据失败", e);
            return null;
        }
    }
    
    /**
     * 从CommandResult解析BigDecimal
     */
    private BigDecimal parseCommandResultToBigDecimal(CommandResult result) {
        if (result == null || !result.isSuccess() || result.getOutput() == null || result.getOutput().trim().isEmpty()) {
            return null;
        }
        return parseBigDecimal(result.getOutput());
    }
    
    /**
     * 从CommandResult解析Long
     */
    private Long parseCommandResultToLong(CommandResult result) {
        if (result == null || !result.isSuccess() || result.getOutput() == null || result.getOutput().trim().isEmpty()) {
            return null;
        }
        return parseLong(result.getOutput());
    }
    
    /**
     * 从CommandResult解析磁盘使用率（格式：设备|挂载点|文件系统|总容量|已用|使用率）
     */
    private List<DiskUsageInfo> parseDiskUsageFromCommand(CommandResult result) {
        List<DiskUsageInfo> diskUsageList = new ArrayList<>();
        
        if (result == null || !result.isSuccess() || result.getOutput() == null || result.getOutput().trim().isEmpty()) {
            return diskUsageList;
        }
        
        Set<String> seenDevices = new HashSet<>();
        String[] lines = result.getOutput().trim().split("\\n");
        
        for (String line : lines) {
            String[] parts = line.split("\\|");
            if (parts.length >= 6) {
                try {
                    String device = parts[0].trim();
                    String mountPoint = parts[1].trim();
                    String fileSystem = parts[2].trim();
                    String totalStr = parts[3].trim();
                    String usedStr = parts[4].trim();
                    String usageStr = parts[5].trim();
                    
                    // 去重
                    if (seenDevices.contains(device)) {
                        continue;
                    }
                    seenDevices.add(device);
                    
                    DiskUsageInfo diskUsage = DiskUsageInfo.builder()
                        .mountPoint(mountPoint)
                        .fileSystem(fileSystem)
                        .totalSize(new BigDecimal(totalStr))
                        .usedSize(new BigDecimal(usedStr))
                        .usagePercent(new BigDecimal(usageStr))
                        .build();
                    diskUsageList.add(diskUsage);
                } catch (NumberFormatException e) {
                    log.warn("解析磁盘使用率失败: {}", line, e);
                }
            }
        }
        
        return diskUsageList;
    }
    
    @Override
    public OsTypeEnum getSupportedOsType() {
        return OsTypeEnum.LINUX;
    }
}
