const API_BASE_URL = "https://hyperapp.in";

import {
  IMultiTransaction,
  MultiTransactionType,
  TransactionStatus,
  OverallStatus,
  TokenURI,
} from "../types/activity";

// Define interface for the output details
export interface OutputDetails {
  amount: string;
  amountFormatted: string;
  amountUsd: string;
  minimumAmount: string;
}

// Define interface for the request parameters
export interface MultiRelayBuyQuoteParams {
  username: string;
  amount: number;
  outputToken: string;
  outputChainId: number;
}

// Balance interfaces
export interface TokenBalance {
  // Add balance properties as needed
  symbol: string;
  balance: string;
  balanceInUsd: string;
  // Other properties from the API response
}

export interface BalanceResponse {
  success: boolean;
  data: TokenBalance[];
}

export interface MultiRelaySellQuoteParams {
  username: string;
  amount: number;
  inputToken: string;
  chainId: number;
}

export interface MultiRelaySwapQuoteParams {
  username: string;
  userBalance: any[] | undefined;
  outputToken: string;
  outputChainId: number;
  inputAmount?: number;
  proMode?: boolean;
  txsGasLimit?: number;
}

export interface BuyFlowParams {
  username: string;
  amount: number;
  outputToken: string;
  outputChainId: number;
  txGasLimit: number;
}

export interface SellFlowParams {
  username: string;
  amount: number;
  inputToken: string;
  chainId: number;
}

export interface SwapInput {
  chainId: number;
  tokenAddress: string;
  amount: string;
}

export interface SwapFlowParams {
  username: string;
  userBalance: any[] | undefined;
  outputToken: string | undefined;
  outputChainId: number | undefined;
  metadata: {
    inputToken: TokenURI;
    outputToken: TokenURI;
  };
  inputAmount?: number;
  proMode?: boolean;
  txsGasLimit?: number;
}

export interface TransactionResult {
  chainId: number;
  success: boolean;
  txnHash: string;
  requestId?: string;
}

export interface TransferFlowParams {
  username: string;
  inputAmount: string;
  outputToken: string;
  outputDecimals: number;
  outputChainId: number;
  recipient: string;
  userBalance: any[];
  metadata?: any;
}

export interface TransferResponse {
  spendPlan: {
    total_withdrawn: string;
    spend_distribution: { [key: string]: string };
    remaining_balance: string;
  };
  onChainTransfer?: {
    chainId: number;
    txHash: string;
  };
  relayTransfer?: {
    type: string;
    success: boolean;
    evmTransactions: TransactionResult[];
    solanaTransactions: TransactionResult[];
  };
  outputDetails: {
    amount: string;
    minimumAmount: string;
    amountFormatted: string;
  };
}

export interface User {
  username: string;
  walletAddress: string;
  solana_program_wallet: string;
  ens: string;
}

export interface TokenDetail {
  amount: string;
  amountFormatted: string;
  tokenAddress: string;
  tokenName: string;
  tokenSymbol: string;
  receiver?: User;
}

export interface ChainTokenDetails {
  [chainId: string]: TokenDetail[];
}

export interface ChainTransactions {
  [chainId: string]: {
    [txHash: string]: string;
  };
}

export interface TransactionMetadata {
  senderDetails: User;
  receiverDetails: User[];
  inputAmounts: ChainTokenDetails;
  destinationAmounts: ChainTokenDetails;
  status: string;
  lastUpdatedTimestamp: number;
  transactions: ChainTransactions;
  requestIdsMap?: {
    [chainId: string]: string;
  };
}

export interface ActivityItem {
  _id: string;
  multiTransactionId: string;
  sender: User;
  transactionType: string;
  transactionDescription: string;
  receivers: User[];
  sourceChains: number[];
  destinationChains: number[];
  inputTokens: ChainTokenDetails;
  outputTokens: ChainTokenDetails;
  transactions: ChainTransactions;
  overallStatus: string;
  metadata: TransactionMetadata;
  createdTimestamp: number;
  lastUpdatedTimestamp: number;
  updatedAt: string;
  __v: number;
}

export interface ActivityResponse {
  success: boolean;
  data: IMultiTransaction[];
}

/**
 * Fetches a buy quote from the multi-relay endpoint
 * @param params Request parameters for the quote
 * @param apiKey The wallet SDK key for authorization
 * @returns The output details from the quote response
 */
export const getMultiRelayBuyQuote = async (
  params: MultiRelayBuyQuoteParams,
  apiKey: string
): Promise<OutputDetails | string> => {
  try {
    const response = await fetch(`${API_BASE_URL}/relay/buy/quote`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `${apiKey}`,
      },
      body: JSON.stringify(params),
    });

    if (!response.ok) {
      const errorData = await response.json();
      console.log("errorData", errorData);
      return errorData.message;
    }

    const data = await response.json();
    return data.outputDetails || null;
  } catch (error) {
    console.error("Error fetching multi relay buy quote:", error);
    return "Error fetching quote";
  }
};

export const getMultiRelaySellQuote = async (
  params: MultiRelaySellQuoteParams,
  apiKey: string
): Promise<OutputDetails | string> => {
  try {
    const response = await fetch(`${API_BASE_URL}/relay/sell/quote`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `${apiKey}`,
      },
      body: JSON.stringify(params),
    });

    if (!response.ok) {
      const errorData = await response.json();
      console.log("errorData", errorData);
      return errorData.message;
    }

    const data = await response.json();
    return data.outputDetails || null;
  } catch (error) {
    console.error("Error fetching multi relay buy quote:", error);
    return "Error fetching quote";
  }
};

export const getMultiRelaySwapQuote = async (
  params: MultiRelaySwapQuoteParams,
  apiKey: string
): Promise<OutputDetails | any> => {
  try {
    const response = await fetch(`${API_BASE_URL}/relay/swap/quote`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `${apiKey}`,
      },
      body: JSON.stringify(params),
    });

    if (!response.ok) {
      const errorData = await response.json();
      console.log("errorData", errorData);
      return errorData;
    }

    const data = await response.json();
    return data.outputDetails || null;
  } catch (error) {
    console.error("Error fetching multi relay buy quote:", error);
    return "Error fetching quote";
  }
};

/**
 * Fetches the user's crypto balance
 * @param username The user's username
 * @param apiKey The wallet SDK key for authorization
 * @returns The user's crypto balance data
 */
export const getUserCryptoBalance = async (
  username: string,
  apiKey: string
): Promise<BalanceResponse | null> => {
  try {
    const response = await fetch(
      `${API_BASE_URL}/v1/api/balance/crypto?username=${username}`,
      {
        headers: {
          Authorization: `${apiKey}`,
        },
      }
    );
    if (!response.ok) throw new Error("Failed to fetch balance");
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("Error fetching crypto balance:", error);
    return null;
  }
};

/**
 * Executes a buy flow transaction
 * @param params The buy flow parameters
 * @param apiKey The wallet SDK key for authorization
 * @returns The transaction response
 */
export const executeBuyFlow = async (
  params: BuyFlowParams,
  apiKey: string
): Promise<any> => {
  try {
    const response = await fetch(`${API_BASE_URL}/relay/buy/full-flow`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `${apiKey}`,
      },
      body: JSON.stringify(params),
    });

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    return await response.json();
  } catch (error) {
    console.error("Error executing buy flow:", error);
    throw error;
  }
};

/**
 * Executes a sell flow transaction
 * @param params The sell flow parameters
 * @param apiKey The wallet SDK key for authorization
 * @returns The transaction response
 */
export const executeSellFlow = async (
  params: SellFlowParams,
  apiKey: string
): Promise<any> => {
  try {
    const response = await fetch(`${API_BASE_URL}/relay/sell/full-flow`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `${apiKey}`,
      },
      body: JSON.stringify(params),
    });

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    return await response.json();
  } catch (error) {
    console.error("Error executing sell flow:", error);
    throw error;
  }
};

/**
 * Executes a swap flow transaction
 * @param params The swap flow parameters
 * @param apiKey The wallet SDK key for authorization
 * @returns The transaction response
 */
export const executeSwapFlow = async (
  params: SwapFlowParams,
  apiKey: string
): Promise<any> => {
  try {
    const response = await fetch(`${API_BASE_URL}/relay/swap/full-flow`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `${apiKey}`,
      },
      body: JSON.stringify(params),
    });

    if (!response.ok) {
      throw new Error("Network response was not ok");
    }

    return await response.json();
  } catch (error) {
    console.error("Error executing swap flow:", error);
    throw error;
  }
};

export const executeTransferFlow = async (
  params: TransferFlowParams,
  apiKey: string
): Promise<TransferResponse> => {
  try {
    // Log the request parameters with detailed balance info
    console.log("Transfer Flow Request Details:", {
      username: params.username,
      inputAmount: params.inputAmount,
      inputAmountFormatted: `${
        Number(params.inputAmount) / Math.pow(10, params.outputDecimals)
      } USDC`,
      outputToken: params.outputToken,
      outputChainId: params.outputChainId,
      recipient: params.recipient,
      availableBalance: params.userBalance.find(
        (token) => token.chainId === params.outputChainId
      )?.balance,
    });

    // Validate required parameters
    if (
      !params.username ||
      !params.inputAmount ||
      !params.outputToken ||
      !params.outputChainId ||
      !params.recipient
    ) {
      throw new Error("Missing required parameters");
    }

    // Validate userBalance array
    if (!Array.isArray(params.userBalance) || params.userBalance.length === 0) {
      throw new Error("Invalid user balance data");
    }

    // // Find the token balance for the output chain
    // const tokenBalance = params.userBalance.find(
    //   (token) => token.chainId === params.outputChainId
    // );

    // if (!tokenBalance) {
    //   throw new Error(`No balance found for chain ${params.outputChainId}`);
    // }

    const response = await fetch(`${API_BASE_URL}/relay/transfer/full-flow`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: apiKey,
      },
      body: JSON.stringify(params),
    });

    // Log the response status and headers
    console.log("Transfer Flow Response Status:", response.status);
    console.log("Transfer Flow Response Headers:", {
      "content-type": response.headers.get("content-type"),
      "content-length": response.headers.get("content-length"),
    });

    if (!response.ok) {
      const errorData = await response.json();
      console.error("Transfer Flow Error Response:", errorData);
      throw new Error(errorData.message || "Transfer failed");
    }

    const data = await response.json();
    console.log("Transfer Flow Success Response:", data);
    return data;
  } catch (error: any) {
    console.error("Error executing transfer flow:", {
      error,
      message: error.message,
      params: JSON.stringify(params, null, 2),
    });
    throw error;
  }
};

export const getMultiTransactionsList = async (
  username: string,
  apiKey: string
): Promise<ActivityResponse | null> => {
  try {
    const response = await fetch(
      `${API_BASE_URL}/api/multiTransactions/list?username=${username}`,
      {
        headers: {
          Authorization: `${apiKey}`,
        },
      }
    );
    if (!response.ok) throw new Error("Failed to fetch activity");
    const data = await response.json();
    return data;
  } catch (error) {
    console.error("Error fetching activity:", error);
    return null;
  }
};
export { API_BASE_URL };
