/**
 * Heartbeat — sends periodic status updates to TIP routing server.
 * POST /api/proxy/heartbeat every 30s.
 */
import * as https from "https";
import * as http from "http";

export interface HeartbeatPayload {
  token: string;
  ip?: string;
  port: number;
  bytesProxied: number;
  requestsProxied: number;
  latencyMs?: number;
  version: string;
}

export interface HeartbeatResult {
  ok: boolean;
  latencyMs: number;
  error?: string;
}

function postJson(url: string, body: unknown): Promise<{ status: number; latencyMs: number }> {
  return new Promise((resolve, reject) => {
    const start = Date.now();
    const json = JSON.stringify(body);
    const parsed = new URL(url);
    const mod = parsed.protocol === "https:" ? https : http;

    const req = mod.request(
      {
        hostname: parsed.hostname,
        port: parsed.port || (parsed.protocol === "https:" ? 443 : 80),
        path: parsed.pathname + parsed.search,
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Content-Length": Buffer.byteLength(json),
          "User-Agent": "TIP-Agent/1.0.0",
        },
        timeout: 10_000,
      },
      (res) => {
        res.resume();
        resolve({ status: res.statusCode ?? 0, latencyMs: Date.now() - start });
      }
    );

    req.on("timeout", () => { req.destroy(); reject(new Error("timeout")); });
    req.on("error", reject);
    req.write(json);
    req.end();
  });
}

export async function sendHeartbeat(
  serverUrl: string,
  payload: HeartbeatPayload
): Promise<HeartbeatResult> {
  const url = `${serverUrl}/api/proxy/heartbeat`;
  try {
    const { status, latencyMs } = await postJson(url, payload);
    return { ok: status >= 200 && status < 300, latencyMs };
  } catch (err) {
    return { ok: false, latencyMs: 0, error: String(err) };
  }
}

export function startHeartbeatLoop(
  serverUrl: string,
  getPayload: () => HeartbeatPayload,
  onResult?: (r: HeartbeatResult) => void,
  intervalMs = 30_000
): NodeJS.Timeout {
  const tick = async () => {
    const result = await sendHeartbeat(serverUrl, getPayload());
    onResult?.(result);
  };
  tick();
  return setInterval(tick, intervalMs);
}
