import { Injectable, Logger } from '@nestjs/common';
import * as os from 'os';
import { exec } from 'child_process';
import { promisify } from 'util';
import { RedisService } from '../../infrastructure/redis/redis.service';
import { WorkerHeartbeatService } from '../../workers/worker-heartbeat.service';

const execAsync = promisify(exec);

export interface DiskInfo { mount: string; total: string; used: string; free: string; percent: number }
export interface ProcessInfo { pid: number; cpu: string; mem: string; name: string; desc: string; command: string }
export interface ServerInfo {
  name: string; role: string; hostname: string;
  cpu: { model: string; cores: number; usagePercent: number };
  memory: { total: string; used: string; free: string; percent: number };
  disks: DiskInfo[];
  uptime: string;
  processes: ProcessInfo[];
  network: { publicIp: string; privateIp: string; domains: string[] };
}

const SSH_KEY_PATH = process.env.SSH_KEY_PATH || '/home/ubuntu/.ssh/wangdl.pem';
const REMOTE_HOST = '10.2.0.7';

const ALIASES: Record<string, { name: string; desc: string }> = {
  'mysqld': { name: 'MySQL 8.0', desc: '业务数据库' },
  'redis-server': { name: 'Redis 7', desc: '缓存/队列' },
  'qdrant': { name: 'Qdrant', desc: '向量索引库' },
  'nginx': { name: 'Nginx', desc: '反向代理' },
  'gitea': { name: 'Gitea', desc: '代码仓库' },
  'dist/src/main.js': { name: 'NestJS API', desc: '知习后端' },
  'dist/main.js': { name: 'NestJS API', desc: '知习后端' },
  'act_runner': { name: 'Gitea Runner', desc: 'CI/CD' },
  'hermes': { name: 'Hermes Agent', desc: 'AI Agent' },
  'rag-worker': { name: 'RAG Worker', desc: '文档解析' },
  'main.py': { name: 'Python Worker', desc: '后台任务' },
  'python3': { name: 'Python', desc: 'Python 进程' },
  'node ': { name: 'Node.js', desc: 'Node 进程' },
  'dockerd': { name: 'Docker', desc: '容器引擎' },
  'containerd': { name: 'containerd', desc: '容器管理' },
  'systemd-journald': { name: '日志服务', desc: '系统日志' },
  'snapd': { name: 'Snapd', desc: '包管理' },
  'multipathd': { name: '存储多路径', desc: '磁盘管理' },
  'YDEyes': { name: '腾讯云监控', desc: '安全监控' },
  'barad_agent': { name: '云监控上报', desc: '指标采集' },
};

function friendly(cmd: string): { name: string; desc: string } {
  for (const [p, info] of Object.entries(ALIASES))
    if (cmd.includes(p)) return info;
  const s = cmd.split('/').pop()?.slice(0, 20) || cmd.slice(0, 18);
  return { name: s, desc: '' };
}

function parsePsLine(line: string): ProcessInfo {
  const p = line.trim().split(/\s+/);
  const pid = parseInt(p[1]) || 0; // col 1 = PID
  const cpu = (p[2] || '0') + '%';
  const mem = (p[3] || '0') + '%';
  const cmd = p.slice(10).join(' ');
  const info = friendly(cmd);
  return { pid, cpu, mem, name: info.name, desc: info.desc, command: cmd.slice(0, 80) };
}

function chineseUptime(sec: number): string {
  const d = Math.floor(sec / 86400), h = Math.floor((sec % 86400) / 3600), m = Math.floor((sec % 3600) / 60);
  return `${d}天${h}时${m}分`;
}

@Injectable()
export class AdminServersService {
  private readonly logger = new Logger(AdminServersService.name);

  constructor(private readonly redis: RedisService) {}

  async getLocalMetrics(): Promise<ServerInfo> {
    const cpus = os.cpus();
    const total = os.totalmem(), free = os.freemem(), used = total - free;
    const cpuPct = Math.min(100, Math.round((os.loadavg()[0] / cpus.length) * 100));

    const disks: DiskInfo[] = [];
    for (const m of ['/', '/data']) {
      try {
        const { stdout } = await execAsync(`df -h ${m} | tail -1 | awk '{printf "%s,%s,%s,%d",$2,$3,$4,int($5)}'`);
        const parts = stdout.trim().split(',');
        if (parts.length >= 3) disks.push({ mount: m, total: parts[0], used: parts[1], free: parts[2], percent: parseInt(parts[3]) || 0 });
        else disks.push({ mount: m, total: '-', used: '-', free: '-', percent: 0 });
      } catch { disks.push({ mount: m, total: '-', used: '-', free: '-', percent: 0 }) }
    }

    let procs: ProcessInfo[] = [];
    try {
      const { stdout } = await execAsync("ps auxww --sort=-%mem --no-headers | head -10");
      procs = stdout.trim().split('\n').filter(l => l).map(parsePsLine);
    } catch {}

    const nets = os.networkInterfaces();
    const privIp = Object.values(nets).flat().find(n => n?.family === 'IPv4' && !n.internal)?.address || '172.21.0.4';

    return {
      name: '蜂驰云 8核32G', role: '生产核心', hostname: os.hostname(),
      cpu: { model: cpus[0]?.model || '', cores: cpus.length, usagePercent: cpuPct },
      memory: { total: (total / 1e9).toFixed(1) + 'G', used: (used / 1e9).toFixed(1) + 'G', free: (free / 1e9).toFixed(1) + 'G', percent: Math.round((used / total) * 100) },
      disks, uptime: chineseUptime(os.uptime()), processes: procs,
      network: { publicIp: '120.53.227.155', privateIp: privIp, domains: ['api.longde.cloud', 'admin.longde.cloud'] },
    };
  }

  async getRemoteMetrics(): Promise<ServerInfo | null> {
    const run = (cmd: string) =>
      execAsync(`ssh -o StrictHostKeyChecking=no -o ConnectTimeout=2 -i ${SSH_KEY_PATH} ubuntu@${REMOTE_HOST} '${cmd.replace(/'/g, "'\\''")}'`, { timeout: 4000 })
        .then(r => r.stdout.trim()).catch(() => '');

    try {
      const [hostname, privIp, load, cores, memStr, diskRoot, diskData, uptimeRaw, procRaw] = await Promise.all([
        run('hostname'),
        run("hostname -I | awk '{print $1}'"),
        run("cat /proc/loadavg | awk '{print $1}'"),
        run('cat /proc/cpuinfo | grep processor | wc -l'),
        run("free -m | awk '/Mem/{printf \"%.1fG,%.1fG,%.1fG,%d\",$2/1024,$3/1024,$4/1024,int($3/$2*100)}'"),
        run("df -h / | awk 'NR==2{printf \"%s,%s,%s,%d\",$2,$3,$4,int($5)}'"),
        run("df -h /data 2>/dev/null | awk 'NR==2{printf \"%s,%s,%s,%d\",$2,$3,$4,int($5)}'"),
        run("uptime -p | sed 's/up //'"),
        run("ps auxww --sort=-%mem --no-headers 2>/dev/null | head -8"),
      ]);

      const load1 = parseFloat(load) || 0;
      const cpuCores = parseInt(cores) || 4;
      const cpuPct = Math.min(100, Math.round((load1 / Math.max(cpuCores, 1)) * 100));
      const memParts = memStr.split(',');
      const memPct = parseInt(memParts[3]) || 0;
      const drParts = diskRoot.split(',');
      const ddParts = diskData.split(',');
      const disks: DiskInfo[] = [{ mount: '/', total: drParts[0] || '-', used: drParts[1] || '-', free: drParts[2] || '-', percent: parseInt(drParts[3]) || 0 }];
      if (ddParts.length >= 3 && diskData !== diskRoot) disks.push({ mount: '/data', total: ddParts[0], used: ddParts[1], free: ddParts[2], percent: parseInt(ddParts[3]) || 0 });

      const procs: ProcessInfo[] = procRaw.split('\n').filter(l => /^\S+\s+\d+\s/.test(l)).map(parsePsLine);

      let up = uptimeRaw || '';
      up = up.replace(/(\d+)\s+weeks?,?\s*/g, '$1周').replace(/(\d+)\s+days?,?\s*/g, '$1天').replace(/(\d+)\s+hours?,?\s*/g, '$1时').replace(/(\d+)\s+minutes?/g, '$1分');

      return {
        name: '轻量云 4核4G', role: '工具/辅助', hostname: hostname || 'remote',
        cpu: { model: 'Intel Xeon (Lighthouse)', cores: cpuCores, usagePercent: cpuPct },
        memory: { total: memParts[0] || '-', used: memParts[1] || '-', free: memParts[2] || '-', percent: memPct },
        disks, uptime: up || '-', processes: procs,
        network: { publicIp: '81.70.187.179', privateIp: privIp || '10.2.0.7', domains: ['longde.cloud', 'git.longde.cloud'] },
      };
    } catch (err: any) {
      this.logger.warn('Remote metrics failed: ' + err.message);
      return null;
    }
  }

  async getAllMetrics() {
    const [local, remote] = await Promise.all([this.getLocalMetrics(), this.getRemoteMetrics()]);
    return { servers: [local, ...(remote ? [remote] : [])] };
  }

  // ═══ Worker Heartbeats ═══

  async getWorkerHeartbeats() {
    try {
      const statuses = await WorkerHeartbeatService.computeStatuses(this.redis);
      return { workers: statuses };
    } catch (err: any) {
      this.logger.warn(`Worker heartbeat query failed: ${err.message}`);
      return { workers: [] };
    }
  }

  // ═══ Health Checks ═══

  async getHealthChecks() {
    const local = await this.checkLocal();
    const localResult = { serverName: '蜂驰云 8核32G', services: local };
    const remoteResult = await this.checkRemote();
    return remoteResult ? [localResult, remoteResult] : [localResult];
  }

  private async checkLocal() {
    const checks = [
      this.checkService('MySQL', 'mysql', 3306),
      this.checkService('Redis', 'redis', 6379),
      this.checkService('Qdrant', 'qdrant', 6333),
      this.checkService('Nginx', 'nginx', 80),
      this.checkProcess('NestJS API', 'dist/src/main.js'),
      this.checkProcess('Gitea Runner', 'act_runner'),
      this.checkProcess('Hermes Agent', 'hermes'),
    ];

    // Also check Docker
    checks.push(this.checkDocker());
    // Check Gitea API
    checks.push(this.checkGiteaUrl());

    return Promise.all(checks);
  }

  private async checkRemote() {
    try {
      const results = await Promise.all([
        this.checkRemoteService('MySQL', 'mysql', 3306),
        this.checkRemoteService('Redis', 'redis', 6379),
        this.checkRemoteService('Nginx', 'nginx', 80),
        this.checkRemoteProcess('NestJS API', 'dist/src/main.js'),
        this.checkRemoteDocker(),
      ]);
      return { serverName: '轻量云 4核4G', services: results };
    } catch {
      return null;
    }
  }

  private async checkDocker() {
    try {
      await execAsync('docker ps --format "{{.Names}}"', { timeout: 3000 });
      return { serviceName: 'Docker', status: 'healthy', message: '运行中' };
    } catch {
      return { serviceName: 'Docker', status: 'unhealthy', message: 'Docker 不可达' };
    }
  }

  private async checkRemoteDocker() {
    try {
      await execAsync(`ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 -i ${SSH_KEY_PATH} ubuntu@${REMOTE_HOST} 'docker ps --format "{{.Names}}"'`, { timeout: 5000 });
      return { serviceName: 'Docker', status: 'healthy', message: '运行中' };
    } catch {
      return { serviceName: 'Docker', status: 'unhealthy', message: 'Docker 不可达' };
    }
  }

  private async checkService(name: string, key: string, port: number) {
    try {
      const { stdout } = await execAsync(`ss -tlnp | grep ':${port} ' | head -1`, { timeout: 2000 });
      return { serviceName: name, status: stdout.trim() ? 'healthy' : 'unhealthy', message: stdout.trim() ? '端口监听中' : '端口未监听' };
    } catch {
      return { serviceName: name, status: 'unhealthy', message: `端口 ${port} 不可达` };
    }
  }

  private async checkRemoteService(name: string, key: string, port: number) {
    try {
      const { stdout } = await execAsync(
        `ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 -i ${SSH_KEY_PATH} ubuntu@${REMOTE_HOST} "ss -tlnp | grep ':${port} ' | head -1"`,
        { timeout: 5000 },
      );
      return { serviceName: name, status: stdout.trim() ? 'healthy' : 'unhealthy', message: stdout.trim() ? '端口监听中' : '端口未监听' };
    } catch {
      return { serviceName: name, status: 'unhealthy', message: `端口 ${port} 不可达` };
    }
  }

  private async checkProcess(name: string, search: string) {
    try {
      const { stdout } = await execAsync(`ps aux | grep -v grep | grep '${search}' | head -1`, { timeout: 2000 });
      return { serviceName: name, status: stdout.trim() ? 'healthy' : 'unhealthy', message: stdout.trim() ? '进程活跃' : '进程未找到' };
    } catch {
      return { serviceName: name, status: 'unhealthy', message: '进程检查失败' };
    }
  }

  private async checkRemoteProcess(name: string, search: string) {
    try {
      const { stdout } = await execAsync(
        `ssh -o StrictHostKeyChecking=no -o ConnectTimeout=3 -i ${SSH_KEY_PATH} ubuntu@${REMOTE_HOST} "ps aux | grep -v grep | grep '${search}' | head -1"`,
        { timeout: 5000 },
      );
      return { serviceName: name, status: stdout.trim() ? 'healthy' : 'unhealthy', message: stdout.trim() ? '进程活跃' : '进程未找到' };
    } catch {
      return { serviceName: name, status: 'unhealthy', message: '进程检查失败' };
    }
  }

  private async checkGiteaUrl() {
    try {
      const { stdout } = await execAsync("curl -s -o /dev/null -w '%{http_code}' http://localhost:3000/api/v1/version 2>/dev/null", { timeout: 3000 });
      return { serviceName: 'Gitea', status: stdout.trim().startsWith('2') ? 'healthy' : 'unhealthy', message: stdout.trim().startsWith('2') ? `HTTP ${stdout.trim()}` : 'Gitea API 异常' };
    } catch {
      return { serviceName: 'Gitea', status: 'unhealthy', message: 'Gitea API 不可达' };
    }
  }
}
