// ─────────────────────────────────────────────────────────────────────────────
// AI service client (HTTP)
//
// Communicates with a local AI microservice over plain HTTP (Node.js built-in
// `http` module).  Exposes three operations:
//   • `chatWithAI`        – send a message and receive a text response
//   • `checkAiServiceStatus` – health-check endpoint
//   • `fetchJobs`         – retrieve background job definitions from the AI
// ─────────────────────────────────────────────────────────────────────────────

import http from "http"

const AI_SERVICE = process.env.AI_SERVICE_URL || "http://localhost:3001"

// ── Internal helper ──────────────────────────────────────────────────────────

/**
 * Parse a URL string into `{ hostname, port, path }` for use with Node's
 * `http.request` / `http.get`.
 */
function parseUrl(url: string) {
  const u = new URL(url)
  return { hostname: u.hostname, port: parseInt(u.port) || 80, path: u.pathname + u.search }
}

// ── Chat ─────────────────────────────────────────────────────────────────────

/**
 * Send a chat message to the AI service and return its response.
 *
 * Authenticates with the user's JWT so the service can enforce its own
 * per-user rate limits or context isolation.
 *
 * @param message  – The user's chat message (plain text).
 * @param jwtToken – The caller's session JWT (`Bearer <token>`).
 * @returns        The AI's text response.
 * @throws         If the service returns a non-2xx status.
 */
export async function chatWithAI(message: string, jwtToken: string) {
  const body = JSON.stringify({ message })
  const { hostname, port, path } = parseUrl(`${AI_SERVICE}/ai/chat`)

  const text = await new Promise<string>((resolve, reject) => {
    const req = http.request(
      { hostname, port, path, method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${jwtToken}`, "Content-Length": Buffer.byteLength(body) } },
      (res) => {
        let data = ""
        res.on("data", (chunk) => data += chunk)
        res.on("end", () => {
          if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
            resolve(data)
          } else {
            reject(new Error(`AI error ${res.statusCode}: ${data.substring(0, 200)}`))
          }
        })
      }
    )
    req.on("error", reject)
    req.write(body)
    req.end()
  })

  const data = JSON.parse(text)
  return data.response || ""
}

// ── Health check ─────────────────────────────────────────────────────────────

/**
 * Ping the AI service's `/health` endpoint.
 *
 * Expects a JSON response with `{ status: "ok" }`.  Timeout is 3 seconds.
 *
 * @returns `true` when the service is healthy, `false` otherwise.
 */
export async function checkAiServiceStatus() {
  const { hostname, port, path } = parseUrl(`${AI_SERVICE}/health`)
  try {
    await new Promise<void>((resolve, reject) => {
      const req = http.get({ hostname, port, path, timeout: 3000 }, (res) => {
        let data = ""
        res.on("data", (chunk) => data += chunk)
        res.on("end", () => {
          try { resolve(JSON.parse(data).status === "ok" ? undefined : reject(new Error("not ok"))) } catch { reject(new Error("bad response")) }
        })
      })
      req.on("error", reject)
      req.on("timeout", () => { req.destroy(); reject(new Error("timeout")) })
    })
    return true
  } catch {
    return false
  }
}

// ── Job listing ──────────────────────────────────────────────────────────────

/**
 * Fetch available AI background jobs from the service.
 *
 * Returns an empty array on any error (network, parse, timeout) instead of
 * throwing, so callers can degrade gracefully.
 *
 * @returns Array of job descriptors (shape defined by the AI service).
 */
export async function fetchJobs() {
  const { hostname, port, path } = parseUrl(`${AI_SERVICE}/ai/jobs`)
  try {
    const text = await new Promise<string>((resolve, reject) => {
      const req = http.get({ hostname, port, path, timeout: 5000 }, (res) => {
        let data = ""
        res.on("data", (chunk) => data += chunk)
        res.on("end", () => resolve(data))
      })
      req.on("error", reject)
      req.on("timeout", () => { req.destroy(); reject(new Error("timeout")) })
    })
    const data = JSON.parse(text)
    return data.jobs || []
  } catch {
    console.warn("Failed to fetch AI jobs")
    return []
  }
}
