export interface RegisterDeviceRequest {
  organizationSlug: string;
  activationToken: string;
  deviceName: string;
  hostname: string;
  os: string;
  osVersion: string;
  agentVersion: string;
  claudeCodeVersion?: string;
}

export interface RegisterDeviceResponse {
  data: {
    device_id: string;
    device_name: string;
    status: string;
    device_token: string;
  };
}

export interface SubmitPromptRequest {
  promptId: string;
  sessionId: string;
  prompt: string;
  submittedAt: string;
  projectName: string;
  projectPathHash: string;
  projectDetectionSource: string;
  clientVersion: string;
}

export class ApiError extends Error {
  constructor(
    message: string,
    public readonly status: number | null,
  ) {
    super(message);
  }
}

const DEFAULT_TIMEOUT_MS = 10_000;

async function request<T>(
  baseUrl: string,
  path: string,
  init: RequestInit,
  timeoutMs = DEFAULT_TIMEOUT_MS,
): Promise<T> {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(`${baseUrl.replace(/\/$/, '')}${path}`, {
      ...init,
      signal: controller.signal,
      headers: {
        'Content-Type': 'application/json',
        Accept: 'application/json',
        ...init.headers,
      },
    });

    const body: any = await response.json().catch(() => null);

    if (!response.ok) {
      throw new ApiError((body && body.message) || `Request failed with status ${response.status}`, response.status);
    }

    return body as T;
  } catch (error) {
    if (error instanceof ApiError) {
      throw error;
    }

    throw new ApiError(error instanceof Error ? error.message : 'Network error', null);
  } finally {
    clearTimeout(timer);
  }
}

export async function pingApi(baseUrl: string, timeoutMs = 5_000): Promise<boolean> {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);

  try {
    const response = await fetch(`${baseUrl.replace(/\/$/, '')}/up`, { signal: controller.signal });

    return response.ok;
  } catch {
    return false;
  } finally {
    clearTimeout(timer);
  }
}

export function registerDevice(baseUrl: string, payload: RegisterDeviceRequest): Promise<RegisterDeviceResponse> {
  return request(baseUrl, '/api/v1/agent/devices/register', {
    method: 'POST',
    body: JSON.stringify({
      organization_slug: payload.organizationSlug,
      activation_token: payload.activationToken,
      device_name: payload.deviceName,
      hostname: payload.hostname,
      os: payload.os,
      os_version: payload.osVersion,
      agent_version: payload.agentVersion,
      claude_code_version: payload.claudeCodeVersion,
    }),
  });
}

export function submitPrompt(
  baseUrl: string,
  deviceToken: string,
  payload: SubmitPromptRequest,
): Promise<unknown> {
  return request(baseUrl, '/api/v1/agent/prompts', {
    method: 'POST',
    headers: { Authorization: `Bearer ${deviceToken}` },
    body: JSON.stringify({
      prompt_id: payload.promptId,
      session_id: payload.sessionId,
      prompt: payload.prompt,
      submitted_at: payload.submittedAt,
      project_name: payload.projectName,
      project_path_hash: payload.projectPathHash,
      project_detection_source: payload.projectDetectionSource,
      client_version: payload.clientVersion,
    }),
  }, 5_000);
}

export function revokeDevice(baseUrl: string, deviceToken: string): Promise<unknown> {
  return request(baseUrl, '/api/v1/agent/devices/logout', {
    method: 'POST',
    headers: { Authorization: `Bearer ${deviceToken}` },
  }, 5_000);
}

export interface AgentStatusResponse {
  developer: string;
  device: string;
  tracking: string;
  api: string;
  uploaded_today: number;
  last_upload: string | null;
}

export function fetchStatus(baseUrl: string, deviceToken: string): Promise<AgentStatusResponse> {
  return request(baseUrl, '/api/v1/agent/status', {
    method: 'GET',
    headers: { Authorization: `Bearer ${deviceToken}` },
  }, 5_000);
}
