import { db } from '../db/index.js'

interface IntegrationRow {
  id: number
  type: string
  config_json: string
}

export interface DockerHost {
  id: number
  baseUrl: string
}

export function loadDockerHost(integrationId: number): DockerHost | null {
  const row = db
    .prepare('SELECT id, type, config_json FROM integrations WHERE id = ?')
    .get(integrationId) as IntegrationRow | undefined
  if (!row || row.type !== 'docker') return null
  const config = JSON.parse(row.config_json) as Record<string, string>
  const baseUrl = config.baseUrl?.replace(/\/$/, '')
  if (!baseUrl) return null
  return { id: row.id, baseUrl }
}

/** Thin wrapper over the Docker Engine HTTP API - this app talks to dockerd directly rather than
 * shelling out to the `docker` CLI over SSH, since ArchNest's docker integration is already
 * configured with a baseUrl (TCP or proxied socket) pointing straight at the Engine API. */
export async function dockerFetch(host: DockerHost, path: string, init: RequestInit = {}): Promise<Response> {
  const res = await fetch(`${host.baseUrl}${path}`, init)
  if (!res.ok) {
    let message = res.statusText
    try {
      const body = (await res.json()) as { message?: string }
      message = body.message ?? message
    } catch {
      // ignore non-JSON error bodies
    }
    throw new Error(message)
  }
  return res
}

export async function dockerJson<T>(host: DockerHost, path: string, init: RequestInit = {}): Promise<T> {
  const res = await dockerFetch(host, path, init)
  if (res.status === 204) return undefined as T
  return res.json() as Promise<T>
}

/** Docker's `stats`/`logs` endpoints multiplex stdout/stderr into 8-byte-header frames unless the
 * container was created with a tty, in which case the body is already raw text. We don't know
 * which mode a given container used ahead of time, so attempt the frame format and fall back to
 * treating the whole buffer as raw text if it doesn't look like a valid frame stream. */
export function demuxDockerStream(buf: Buffer): string {
  let result = ''
  let offset = 0
  while (offset + 8 <= buf.length) {
    const streamType = buf.readUInt8(offset)
    if (streamType > 2) return buf.toString('utf8')
    const length = buf.readUInt32BE(offset + 4)
    const start = offset + 8
    const end = start + length
    if (end > buf.length) return buf.toString('utf8')
    result += buf.subarray(start, end).toString('utf8')
    offset = end
  }
  if (offset === 0) return buf.toString('utf8')
  return result
}
