/**
 * Federation Queries API Client
 * Handles federated query requests to remote instances
 */

import { apiGet, apiPost } from "./client";

/**
 * Federation message status (matches backend enum)
 */
export enum FederationMessageStatus {
  PENDING = "PENDING",
  DELIVERED = "DELIVERED",
  FAILED = "FAILED",
}

/**
 * Query message details
 */
export interface QueryMessageDetails {
  id: string;
  workspaceId: string;
  connectionId: string;
  messageType: string;
  messageId: string;
  correlationId?: string;
  query?: string;
  response?: unknown;
  status: FederationMessageStatus;
  error?: string;
  createdAt: string;
  updatedAt: string;
  deliveredAt?: string;
}

/**
 * Send query request
 */
export interface SendQueryRequest {
  connectionId: string;
  query: string;
  context?: Record<string, unknown>;
}

/**
 * Send a federated query to a remote instance
 */
export async function sendFederatedQuery(
  connectionId: string,
  query: string,
  context?: Record<string, unknown>
): Promise<QueryMessageDetails> {
  const request: SendQueryRequest = {
    connectionId,
    query,
  };

  if (context) {
    request.context = context;
  }

  return apiPost<QueryMessageDetails>("/api/v1/federation/query", request);
}

/**
 * Fetch all query messages for the workspace
 */
export async function fetchQueryMessages(
  status?: FederationMessageStatus
): Promise<QueryMessageDetails[]> {
  const params = new URLSearchParams();

  if (status) {
    params.append("status", status);
  }

  const queryString = params.toString();
  const endpoint = queryString
    ? `/api/v1/federation/queries?${queryString}`
    : "/api/v1/federation/queries";

  return apiGet<QueryMessageDetails[]>(endpoint);
}

/**
 * Fetch a single query message
 */
export async function fetchQueryMessage(messageId: string): Promise<QueryMessageDetails> {
  return apiGet<QueryMessageDetails>(`/api/v1/federation/queries/${messageId}`);
}

/**
 * Poll for query response with timeout
 * @param messageId - The message ID to poll for
 * @param options - Polling options
 * @returns The query message details when delivered or failed
 * @throws Error if timeout is reached or message fails
 */
export async function pollForQueryResponse(
  messageId: string,
  options?: {
    pollInterval?: number; // milliseconds between polls (default: 500)
    timeout?: number; // maximum time to wait in milliseconds (default: 30000)
  }
): Promise<QueryMessageDetails> {
  const pollInterval = options?.pollInterval ?? 500;
  const timeout = options?.timeout ?? 30000;
  const startTime = Date.now();

  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
  while (true) {
    // Check if timeout has been reached
    if (Date.now() - startTime > timeout) {
      throw new Error(`Query timeout after ${String(timeout)}ms`);
    }

    // Fetch the message
    const message = await fetchQueryMessage(messageId);

    // Check if the message is complete
    if (message.status === FederationMessageStatus.DELIVERED) {
      return message;
    }

    if (message.status === FederationMessageStatus.FAILED) {
      throw new Error(message.error ?? "Query failed");
    }

    // Wait before polling again
    await new Promise((resolve) => setTimeout(resolve, pollInterval));
  }
}
