import { log } from './logger.js';

const RELAY_API = 'https://api.bloby.bot/api';

// ─── Register a new handle ──────────────────────────────────────────────────

export async function registerHandle(
  username: string,
  tier: string,
  walletAddress?: string,
): Promise<{ token: string; relayUrl: string }> {
  const payload: Record<string, string> = { username, tier };
  if (walletAddress) payload.walletAddress = walletAddress;

  const res = await fetch(`${RELAY_API}/register`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  const data = await res.json();

  if (!res.ok) {
    throw new Error(data.error || `Registration failed (${res.status})`);
  }

  return { token: data.token, relayUrl: data.relayUrl };
}

// ─── Check username availability ─────────────────────────────────────────────

export async function checkAvailability(
  username: string,
): Promise<{
  valid: boolean;
  error?: string;
  handles: { tier: string; url: string; paid: boolean; price: number; available: boolean }[];
}> {
  const res = await fetch(`${RELAY_API}/availability/${encodeURIComponent(username)}`);
  return res.json();
}

// ─── Claim a reserved (purchased) handle ────────────────────────────────────

export async function claimReservedHandle(
  handle: string,
  hash: string,
  walletAddress?: string,
): Promise<{ token: string; relayUrl: string }> {
  const payload: Record<string, string> = { handle, hash };
  if (walletAddress) payload.walletAddress = walletAddress;

  const res = await fetch(`${RELAY_API}/handle/claim-reserved`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(payload),
  });

  const data = await res.json();

  if (!res.ok) {
    throw new Error(data.error || `Claim failed (${res.status})`);
  }

  return { token: data.token, relayUrl: data.relayUrl };
}

// ─── Release handle ─────────────────────────────────────────────────────────

export async function releaseHandle(token: string): Promise<void> {
  const res = await fetch(`${RELAY_API}/handle`, {
    method: 'DELETE',
    headers: { Authorization: `Bearer ${token}` },
  });

  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw new Error(data.error || `Release failed (${res.status})`);
  }
}

// ─── Update tunnel URL ──────────────────────────────────────────────────────

export async function updateTunnelUrl(token: string, tunnelUrl: string): Promise<void> {
  const res = await fetch(`${RELAY_API}/tunnel`, {
    method: 'PUT',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({ tunnelUrl }),
  });

  if (!res.ok) {
    const data = await res.json().catch(() => ({}));
    throw new Error(data.error || `Tunnel update failed (${res.status})`);
  }

  log.ok('Relay updated with tunnel URL');
}

// ─── Heartbeat ───────────────────────────────────────────────────────────────

let heartbeatTimer: ReturnType<typeof setInterval> | null = null;

export function startHeartbeat(token: string, tunnelUrl?: string): void {
  stopHeartbeat();

  const beat = async () => {
    try {
      await fetch(`${RELAY_API}/heartbeat`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${token}`,
        },
        body: JSON.stringify(tunnelUrl ? { tunnelUrl } : {}),
      });
    } catch {
      // Silent — next heartbeat will retry
    }
  };

  beat(); // immediate first beat
  heartbeatTimer = setInterval(beat, 30_000); // every 30s
}

export function stopHeartbeat(): void {
  if (heartbeatTimer) {
    clearInterval(heartbeatTimer);
    heartbeatTimer = null;
  }
}

// ─── Disconnect (graceful shutdown) ──────────────────────────────────────────

export async function disconnect(token: string): Promise<void> {
  stopHeartbeat();

  try {
    await fetch(`${RELAY_API}/disconnect`, {
      method: 'POST',
      headers: { Authorization: `Bearer ${token}` },
    });
  } catch {
    // Best-effort — if it fails, heartbeat timeout will mark offline
  }
}
