import {
  BridgeToken,
  Chain,
  Ecosystem,
  GetLeaderboardChangePayload,
  GetPricesPayload,
  GetRoutePayload,
  GetSolanaRoutePayload,
  GetTokenBalancesPayload,
  EVMRoute,
  SolanaRoute,
  Token,
  TokenPrices,
  TransactionHistory,
  TransactionStatus,
} from "@src/models";

let XSWAP_API_URL = "https://xswap.link/api";
// let XSWAP_API_URL = "https://develop-72sp7lmyaa-ew.a.run.app/api/beta/";

export const setApiUrl = (url: string) => {
  XSWAP_API_URL = url;
};

async function _sendRequest<T>(
  urlPath: string,
  options?: RequestInit,
): Promise<T> {
  const response = await fetch(`${XSWAP_API_URL}${urlPath}`, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
      "Cache-Control": "no-cache",
      ...options?.headers,
    },
    ...options,
  });

  if (!response.ok) {
    throw new Error(
      `API request failed with status ${response.status}: ${response.statusText}`,
    );
  }

  return response.json();
}

/**
 * Get swap route based on provided criteria.
 * @param payload required
 * @param abortSignal
 */
export async function getRoute(
  payload: GetRoutePayload,
  abortSignal?: AbortSignal,
): Promise<EVMRoute> {
  return _sendRequest<EVMRoute>("/route", {
    method: "POST",
    body: JSON.stringify(payload),
    signal: abortSignal,
  });
}

/**
 * Get solana swap route based on provided criteria.
 * @param payload required
 * @param abortSignal
 */
export async function getSolanaRoute(
  payload: GetSolanaRoutePayload,
  abortSignal?: AbortSignal,
): Promise<SolanaRoute> {
  return _sendRequest<SolanaRoute>("/solanaRoute", {
    method: "POST",
    body: JSON.stringify(payload),
    signal: abortSignal,
  });
}

/**
 * GET chains based on provided criteria.
 * @param ecosystem optional
 */
export async function getChains(ecosystem?: Ecosystem): Promise<Chain[]> {
  return _sendRequest<Chain[]>(`/chains?data=${JSON.stringify({ ecosystem })}`);
}

/**
 * GET chain data based on provided criteria.
 * @param chainId
 * @param ecosystem optional - Default: {@link DEFAULT_ECOSYSTEM}
 */
export async function getChainData(
  chainId?: string,
  ecosystem?: Ecosystem,
): Promise<Chain> {
  return _sendRequest<Chain>(
    `/chains?data=${JSON.stringify({
      chainId,
      ecosystem,
    })}`,
  );
}

/**
 * GET Tokens based on provided criteria
 * @param chainId required
 * @param address optional
 * @param ecosystem optional but {@link DEFAULT_ECOSYSTEM} will be considered
 */
export async function getTokens(
  chainId: string,
  address?: string,
  ecosystem?: Ecosystem,
): Promise<Token[]> {
  return _sendRequest<Token[]>(
    `/tokens?data=${JSON.stringify({
      chainId,
      address,
      ecosystem,
    })}`,
  );
}

export async function getHistory(payload: { walletAddress: string }) {
  return await _sendRequest<TransactionHistory>(
    `/history?${new URLSearchParams({
      data: JSON.stringify(payload),
    })}`,
  );
}

export async function getPrices(payload: GetPricesPayload) {
  return await _sendRequest<TokenPrices>(
    `/tokenPrices?${new URLSearchParams({
      data: JSON.stringify(payload),
    })}`,
  );
}

export async function getBalances(payload: GetTokenBalancesPayload) {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  return _sendRequest<any>(
    `/tokenBalances?${new URLSearchParams({
      data: JSON.stringify(payload),
    })}`,
  );
}

export async function getTxStatus(payload: { transferId: string }) {
  return await _sendRequest<{ status: TransactionStatus }>(
    `/getTxStatus?${new URLSearchParams({
      data: JSON.stringify(payload), // todo remove once gcp starts working
    })}`,
  );
}

export async function getLeaderboardChange(
  payload: GetLeaderboardChangePayload,
) {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  return _sendRequest<any>(
    `/leaderboardChange?${new URLSearchParams({
      data: JSON.stringify(payload),
    })}`,
  );
}

export async function getBridgeTokens(): Promise<BridgeToken[]> {
  return _sendRequest<BridgeToken[]>(`/bridgeTokens`);
}
