import { NextResponse } from 'next/server';
import { exec, execFile } from 'child_process';
import { promisify } from 'util';
import { readFile } from 'fs/promises';
import { readFileSync } from 'fs';
import os from 'os';

const execAsync = promisify(exec);
const execFileAsync = promisify(execFile);

const IS_MAC = process.platform === 'darwin';
const IS_WSL =
  process.platform === 'linux' &&
  (() => {
    try {
      return readFileSync('/proc/version', 'utf-8').toLowerCase().includes('microsoft');
    } catch {
      return false;
    }
  })();

async function readWindowsCommand(command: string): Promise<string | null> {
  try {
    const { stdout } = await execFileAsync(
      'powershell.exe',
      ['-NoProfile', '-Command', command],
      { timeout: 4000 }
    );
    const value = stdout.replace(/\r/g, '').trim();
    return value || null;
  } catch {
    return null;
  }
}

// Cache slow commands with TTL
let staticCache: {
  chip: string;
  gpu: string;
  brewPackages: Array<{ name: string; version: string }>;
  ts: number;
} | null = null;
const STATIC_TTL = 5 * 60 * 1000; // 5 minutes

let ollamaDiskCache: { value: number; ts: number } | null = null;
const OLLAMA_DISK_TTL = 60 * 1000; // 60 seconds

async function getChipInfo(): Promise<string> {
  try {
    if (IS_MAC) {
      const { stdout } = await execAsync(
        "sysctl -n machdep.cpu.brand_string 2>/dev/null || echo 'Unknown'"
      );
      return stdout.trim();
    }
    if (IS_WSL) {
      const winCpu = await readWindowsCommand(
        '(Get-CimInstance Win32_Processor | Select-Object -First 1 -ExpandProperty Name)'
      );
      if (winCpu) return winCpu;
    }
    // Linux / WSL2
    const { stdout } = await execAsync(
      "lscpu 2>/dev/null | grep 'Model name' | sed 's/.*:\\s*//' || cat /proc/cpuinfo | grep 'model name' | head -1 | sed 's/.*: //'"
    );
    return stdout.trim() || 'Unknown';
  } catch {
    return 'Unknown';
  }
}

async function getDiskSpace(): Promise<{ total: number; used: number; free: number }> {
  try {
    const { stdout } = await execAsync("df -k / | tail -1 | awk '{print $2, $3, $4}'");
    const [total, used, free] = stdout
      .trim()
      .split(' ')
      .map(n => parseInt(n) * 1024);
    return { total, used, free };
  } catch {
    return { total: 0, used: 0, free: 0 };
  }
}

async function getOllamaModelsDiskUsage(): Promise<number> {
  try {
    const { stdout } = await execAsync("du -sk ~/.ollama/models 2>/dev/null | awk '{print $1}'", {
      timeout: 5000,
    });
    return parseInt(stdout.trim()) * 1024 || 0;
  } catch {
    return 0;
  }
}

async function getGpuInfo(): Promise<string> {
  try {
    if (IS_MAC) {
      const { stdout } = await execAsync(
        "system_profiler SPDisplaysDataType 2>/dev/null | grep 'Chipset Model' | sed 's/.*: //'",
        { timeout: 5000 }
      );
      return stdout.trim() || 'Apple Silicon (integrated)';
    }
    // Linux / WSL2 — try nvidia-smi first, fall back to lspci
    try {
      const { stdout } = await execAsync(
        'nvidia-smi --query-gpu=name --format=csv,noheader 2>/dev/null | head -1',
        { timeout: 3000 }
      );
      if (stdout.trim()) return stdout.trim();
    } catch {
      /* no nvidia-smi */
    }
    const { stdout } = await execAsync(
      "lspci 2>/dev/null | grep -i 'vga\\|3d' | sed 's/.*: //' | head -1"
    );
    return stdout.trim() || 'Unknown';
  } catch {
    return IS_MAC ? 'Apple Silicon (integrated)' : 'Unknown';
  }
}

async function getBrewPackages(): Promise<Array<{ name: string; version: string }>> {
  const targets = ['ollama', 'whisper-cpp', 'ffmpeg'];
  const results: Array<{ name: string; version: string }> = [];

  if (IS_MAC) {
    for (const pkg of targets) {
      try {
        const { stdout } = await execFileAsync('brew', ['list', '--versions', pkg], {
          timeout: 3000,
        });
        const parts = stdout.trim().split(' ');
        if (parts.length >= 2) {
          results.push({ name: parts[0], version: parts.slice(1).join(' ') });
        }
      } catch {
        // not installed
      }
    }
  } else {
    // Linux / WSL2 — report installed tools in a stable way (avoid noisy shell errors).
    for (const pkg of targets) {
      try {
        if (pkg === 'ffmpeg') {
          const { stdout } = await execAsync('ffmpeg -version 2>/dev/null | head -1', {
            timeout: 3000,
          });
          if (stdout.trim()) {
            results.push({ name: pkg, version: stdout.trim() });
          }
          continue;
        }

        if (pkg === 'whisper-cpp') {
          const { stdout } = await execAsync('command -v whisper-cli 2>/dev/null', { timeout: 2000 });
          const path = stdout.trim();
          if (path) {
            results.push({ name: pkg, version: `installed (${path})` });
          }
          continue;
        }

        // ollama on Linux/WSL may be a Windows-hosted daemon; prefer API version if reachable.
        if (pkg === 'ollama') {
          const ollamaUrl = process.env.OLLAMA_URL || process.env.OLLAMA_HOST || 'http://localhost:11434';
          const normalized = ollamaUrl.startsWith('http') ? ollamaUrl : `http://${ollamaUrl}`;
          try {
            const res = await fetch(`${normalized.replace(/\/+$/, '')}/api/version`, {
              cache: 'no-store',
              signal: AbortSignal.timeout(2500),
            });
            if (res.ok) {
              const data = (await res.json()) as { version?: string };
              if (data.version) {
                results.push({ name: pkg, version: data.version });
                continue;
              }
            }
          } catch {
            // fall through to local binary check
          }

          const { stdout } = await execAsync('command -v ollama 2>/dev/null', { timeout: 2000 });
          const path = stdout.trim();
          if (path) {
            const { stdout: ver } = await execAsync('ollama --version 2>/dev/null | head -1', {
              timeout: 2000,
            });
            const v = ver.trim();
            results.push({ name: pkg, version: v || `installed (${path})` });
          }
        }
      } catch {
        // skip unavailable tool
      }
    }
  }
  return results;
}

async function getStaticInfo() {
  if (staticCache && Date.now() - staticCache.ts < STATIC_TTL) return staticCache;
  const [chip, gpu, brewPackages] = await Promise.all([
    getChipInfo(),
    getGpuInfo(),
    getBrewPackages(),
  ]);
  staticCache = { chip, gpu, brewPackages, ts: Date.now() };
  return staticCache;
}

// P5: Eagerly warm static cache on module load (system_profiler takes 2-3s)
getStaticInfo().catch(() => {});

async function getCachedOllamaDiskUsage(): Promise<number> {
  if (ollamaDiskCache && Date.now() - ollamaDiskCache.ts < OLLAMA_DISK_TTL)
    return ollamaDiskCache.value;
  const value = await getOllamaModelsDiskUsage();
  ollamaDiskCache = { value, ts: Date.now() };
  return value;
}

// macOS: vm_stat gives accurate memory breakdown (os.freemem() excludes reclaimable cache)
// Linux: /proc/meminfo gives accurate breakdown
async function getAccurateMemory(): Promise<{
  total: number;
  appMemory: number;
  cached: number;
  free: number;
  pressure: string;
}> {
  const totalMem = os.totalmem();

  if (IS_MAC) {
    try {
      const { stdout } = await execAsync('vm_stat', { timeout: 2000 });
      const pageSizeMatch = stdout.match(/page size of (\d+) bytes/);
      const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1]) : 16384;
      const parse = (label: string): number => {
        const match = stdout.match(new RegExp(`${label}:\\s+(\\d+)`));
        return match ? parseInt(match[1]) * pageSize : 0;
      };
      const active = parse('Pages active');
      const wired = parse('Pages wired down');
      const inactive = parse('Pages inactive');
      const purgeable = parse('Pages purgeable');
      const speculative = parse('Pages speculative');
      const free = parse('Pages free');
      const compressor = parse('Pages occupied by compressor');

      const appMemory = active + wired + compressor;
      const cached = inactive + purgeable + speculative;

      const ratio = appMemory / totalMem;
      const pressure = ratio > 0.85 ? 'critical' : ratio > 0.7 ? 'warning' : 'normal';

      return { total: totalMem, appMemory, cached, free, pressure };
    } catch {
      // fall through to generic fallback
    }
  } else {
    // Linux / WSL2 — parse /proc/meminfo
    try {
      const raw = await readFile('/proc/meminfo', 'utf-8');
      const parse = (key: string): number => {
        const match = raw.match(new RegExp(`${key}:\\s+(\\d+)`));
        return match ? parseInt(match[1]) * 1024 : 0; // /proc/meminfo is in kB
      };
      const total = parse('MemTotal');
      const free = parse('MemFree');
      const buffers = parse('Buffers');
      const cached = parse('Cached') + parse('SReclaimable') + buffers;
      const appMemory = total - free - cached;

      const ratio = appMemory / total;
      const pressure = ratio > 0.85 ? 'critical' : ratio > 0.7 ? 'warning' : 'normal';

      if (IS_WSL) {
        const winTotalRaw = await readWindowsCommand(
          '[string](Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory'
        );
        const winTotal = winTotalRaw ? Number.parseInt(winTotalRaw.replace(/\D/g, ''), 10) : 0;
        if (Number.isFinite(winTotal) && winTotal > total) {
          // Keep WSL usage metrics, but report host RAM capacity for Mission Control display.
          return { total: winTotal, appMemory, cached, free, pressure };
        }
      }

      return { total, appMemory, cached, free, pressure };
    } catch {
      // fall through to generic fallback
    }
  }

  // Generic fallback (works everywhere but less accurate)
  const freeMem = os.freemem();
  return {
    total: totalMem,
    appMemory: totalMem - freeMem,
    cached: 0,
    free: freeMem,
    pressure: 'unknown',
  };
}

export async function GET() {
  const [staticInfo, disk, ollamaDisk, memory] = await Promise.all([
    getStaticInfo(),
    getDiskSpace(),
    getCachedOllamaDiskUsage(),
    getAccurateMemory(),
  ]);

  const cpuCount = os.cpus().length;
  const uptime = os.uptime();

  return NextResponse.json({
    chip: staticInfo.chip,
    gpu: staticInfo.gpu,
    memory,
    disk,
    ollamaDiskUsage: ollamaDisk,
    cpuCores: cpuCount,
    uptime,
    platform: IS_WSL ? 'Windows (via WSL2)' : `${os.type()} ${os.release()}`,
    arch: os.arch(),
    nodeVersion: process.version,
    brewPackages: staticInfo.brewPackages,
  });
}
