import type { Client } from 'ssh2'
import { execCommand } from './common.js'

export interface ListeningPort {
  protocol: 'tcp' | 'udp'
  localAddress: string
  localPort: number
  state?: string
  pid?: number
  process?: string
}

export interface PortsMetrics {
  source: 'ss' | 'netstat' | 'none'
  ports: ListeningPort[]
}

function parseSsOutput(output: string): ListeningPort[] {
  const ports: ListeningPort[] = []
  const lines = output.split('\n').slice(1)

  for (const line of lines) {
    const parts = line.trim().split(/\s+/)
    if (parts.length < 5) continue

    const protocol = parts[0]?.toLowerCase()
    if (protocol !== 'tcp' && protocol !== 'udp') continue

    const state = parts[1]
    const localAddr = parts[4]
    if (!localAddr) continue

    const lastColon = localAddr.lastIndexOf(':')
    if (lastColon === -1) continue

    const address = localAddr.substring(0, lastColon).replace(/^\[|\]$/g, '')
    const port = parseInt(localAddr.substring(lastColon + 1), 10)
    if (isNaN(port)) continue

    const entry: ListeningPort = {
      protocol,
      localAddress: address,
      localPort: port,
      state: protocol === 'tcp' ? state : undefined,
    }

    const processInfo = parts[6]
    if (processInfo?.startsWith('users:')) {
      const pidMatch = processInfo.match(/pid=(\d+)/)
      const nameMatch = processInfo.match(/\("([^"]+)"/)
      if (pidMatch) entry.pid = parseInt(pidMatch[1], 10)
      if (nameMatch) entry.process = nameMatch[1]
    }

    ports.push(entry)
  }

  return ports
}

export async function collectPortsMetrics(client: Client): Promise<PortsMetrics> {
  try {
    const ssResult = await execCommand(client, 'ss -tulnp 2>/dev/null')
    if (ssResult.stdout.includes('Local')) {
      return { source: 'ss', ports: parseSsOutput(ssResult.stdout).sort((a, b) => a.localPort - b.localPort) }
    }
    return { source: 'none', ports: [] }
  } catch {
    return { source: 'none', ports: [] }
  }
}
