import { ref } from 'vue';
import { config } from '@/wagmi';
import { readContract, writeContract, getChainId } from '@wagmi/core';
import type { Config } from '@wagmi/core';
import { StakeAbi } from 'kraiken-lib/abis';
import { type Abi, type Address, type Hash, type Hex } from 'viem';
import { getChain } from '@/config';
import logger from '@/utils/logger';

const TAX_FLOOR_DURATION = 60 * 60 * 24 * 3;
interface Contract {
  abi: Abi;
  contractAddress: Address;
}

export const minStake = ref<bigint>(0n);
export const totalSupply = ref(0n);
export const outstandingSupply = ref(0n);

export let StakeContract = getStakeJson();

function getStakeJson() {
  const chainId = getChainId(config as Config);
  const chain = getChain(chainId);

  return { abi: StakeAbi as Abi, contractAddress: chain?.stake } as Contract;
}

export function setStakeContract() {
  logger.contract('setStakeContract');
  StakeContract = getStakeJson();
}

export async function snatchService(assets: bigint, receiver: Address, taxRate: number, positionsToSnatch: Array<bigint>) {
  const result = await writeContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'snatch',
    args: [assets, receiver, taxRate, positionsToSnatch],
  });
  return result;
}

export async function exitPosition(positionId: bigint): Promise<Hash> {
  const result = await writeContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'exitPosition',
    args: [positionId],
  });

  return result;
}

//changeTax
export async function changeTax(positionId: bigint, taxRate: number): Promise<Hash> {
  const result = await writeContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'changeTax',
    args: [positionId, taxRate],
  });

  return result;
}

/**
 * snatch/stake with permit
 */
export async function permitAndSnatch(
  assets: bigint,
  receiver: Address,
  taxRate: number,
  positionsToSnatch: Array<bigint>,
  deadline: bigint,
  v: number,
  r: Hex,
  s: Hex
) {
  const result = await writeContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'permitAndSnatch',
    args: [assets, receiver, taxRate, positionsToSnatch, deadline, v, r, s],
  });
  return result;
}

export async function getTotalSupply() {
  logger.contract('getTotalSupply');
  await setStakeContract();
  const result = await readContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'totalSupply',
    args: [],
  });
  totalSupply.value = result as bigint;
  return result;
}

export async function getOutstandingSupply() {
  logger.contract('getOutstandingSupply');

  const result = await readContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'outstandingStake',
    args: [],
  });

  outstandingSupply.value = result as bigint;
  return result;
}

export async function getTaxDue(positionID: bigint) {
  logger.contract('getTaxDue');
  const result = await readContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'taxDue',
    args: [positionID, TAX_FLOOR_DURATION],
  });
  return result as bigint;
}

export async function payTax(positionID: bigint) {
  const result = await writeContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'payTax',
    args: [positionID],
  });
  return result;
}

export async function assetsToShares(asset: bigint) {
  const result = await readContract(config as Config, {
    abi: StakeContract.abi,
    address: StakeContract.contractAddress,
    functionName: 'assetsToShares',
    args: [asset],
  });
  return result as bigint;
}
