import { ethers } from "ethers";
import {
  ContractCall,
  GenerateStakingCallsParams,
  XSwapCallType,
} from "@src/models";
import {
  findPlaceholderIndex,
  generateUniqueRandomBigNumber,
  IERC20,
  replaceNull,
} from "@src/utils";
import { ERC20Abi } from "@src/contracts";

export const generateStakingCalls = ({
  token,
  staking,
  stakingAbi,
  stakingFunName,
  stakingFunParams,
}: GenerateStakingCallsParams): ContractCall[] => {
  const flatStakingFunParams = stakingFunParams.flat(Infinity);

  if (flatStakingFunParams.filter((param) => param === null).length !== 1) {
    throw new Error(
      "Exactly 1 'null' value should be provided in 'funParams' in order to override token balance",
    );
  }

  const randomBigNumber = generateUniqueRandomBigNumber(
    32,
    flatStakingFunParams,
  );

  const modifiedStakingFunParams = replaceNull(
    stakingFunParams,
    randomBigNumber,
  );

  const approveFunParams = [staking, randomBigNumber];
  const stakingApproveCall: ContractCall = {
    callType: XSwapCallType.FULL_TOKEN_BALANCE,
    target: token,
    callData: IERC20.encodeFunctionData("approve", approveFunParams),
    payload: ethers.utils.defaultAbiCoder.encode(
      ["address", "uint256"],
      [
        token,
        findPlaceholderIndex(
          JSON.stringify(ERC20Abi),
          "approve",
          approveFunParams,
          randomBigNumber,
        ),
      ],
    ),
    value: "0",
  };

  const stakingCall: ContractCall = {
    callType: XSwapCallType.FULL_TOKEN_BALANCE,
    target: staking,
    callData: new ethers.utils.Interface(stakingAbi).encodeFunctionData(
      stakingFunName,
      modifiedStakingFunParams,
    ),
    payload: ethers.utils.defaultAbiCoder.encode(
      ["address", "uint256"],
      [
        token,
        findPlaceholderIndex(
          stakingAbi,
          stakingFunName,
          modifiedStakingFunParams,
          randomBigNumber,
        ),
      ],
    ),
    value: "0",
  };

  return [stakingApproveCall, stakingCall];
};
