/* eslint-disable @typescript-eslint/no-explicit-any */
import { ETHNetwork } from '@nekoproject/networks';
import { ETHWallet } from '@nekoproject/wallets';
import { ethers } from 'ethers';
import axios from 'axios';

//
import { Swap } from '../Swap';
import { CreateOrder, ETHSwapOrderRequest, SetApiParams } from '../types';

export class ETHSwap extends Swap {
  private _createOrderApi: string;
  private _buildTransApi: string;

  constructor(network: ETHNetwork, endpoint: string) {
    let fmt_endpoint: string;
    if (endpoint.endsWith('/')) {
      fmt_endpoint = endpoint.slice(0, endpoint.length - 1);
    } else {
      fmt_endpoint = endpoint;
    }
    super(network, fmt_endpoint);
    this._createOrderApi = this._endpoint + '/v2/swaps/create-order';
    this._buildTransApi = this._endpoint + '/v2/swaps/build-transaction';
  }
  set endpoint(endpoint: string) {
    this._endpoint = endpoint;
  }

  get endpoint() {
    return this._endpoint;
  }

  set api(params: SetApiParams) {
    this._createOrderApi = this._endpoint + params.createOrder;
    this._buildTransApi = this._endpoint + params.buildTransaction;
  }

  /**
   *
   * @param swapRequest
   * @returns
   */
  async createSwapOrder(
    swapRequest: CreateOrder
  ): Promise<ETHSwapOrderRequest> {
    try {
      const unitAmount = ethers.utils.parseUnits(
        swapRequest.srcAmount,
        swapRequest.srcToken.tokenInfo.decimals
      );
      const data = {
        wallet_address: swapRequest.wallet_address,
        slippage: swapRequest.slippage,
        network: 'ETH',
        destDecimals: swapRequest.destToken.tokenInfo.decimals,
        srcDecimals: swapRequest.srcToken.tokenInfo.decimals,
        srcAmount: unitAmount.toString(),
        destToken: swapRequest.destToken.tokenInfo.mintAddress,
        srcToken: swapRequest.srcToken.tokenInfo.mintAddress,
      };
      const orderResquest = await axios.post(this._createOrderApi, data);
      if (orderResquest.data.swap_order) {
        return orderResquest.data.swap_order;
      } else {
        throw new Error(
          `Error create order: ${orderResquest.data?.error?.message}`
        );
      }
    } catch (error) {
      throw new Error(`Error swap token: ${error}`);
    }
  }

  /**
   *
   * @param swapRequest
   * @param wallet
   * @returns
   */
  async swapToken(
    swapRequest: ETHSwapOrderRequest,
    wallet: ETHWallet
  ): Promise<string> {
    try {
      const buildTransactionOrder = {
        slippage: swapRequest.slippage,
        wallet_address: wallet.address,
        network: 'ETH',
        swap_order_id: swapRequest.id.toString(),
      };
      const buildResponse = await axios.post(
        this._buildTransApi,
        buildTransactionOrder
      );
      if (buildResponse.data.transaction) {
        const orderRequest = {
          from: buildResponse.data.transaction.from,
          to: buildResponse.data.transaction.to,
          value: ethers.utils.formatEther(buildResponse.data.transaction.value),
          data: buildResponse.data.transaction.data,
          gasPrice: buildResponse.data.transaction.gasPrice,
          gasLimit: buildResponse.data.transaction.gas,
          chainId: buildResponse.data.transaction.chainId,
        };
        const transactionRequest = await this.network.createTransactionOrder(
          orderRequest,
          wallet
        );
        const hash = await this.network.sendTransaction(
          transactionRequest,
          wallet
        );
        return hash;
      } else {
        throw new Error(
          `Build transaction Error: ${buildResponse.data?.error?.message}`
        );
      }
    } catch (error) {
      throw new Error(`Error swap token: ${error}`);
    }
  }
}
