import { ref } from 'vue';
import { config } from '@/wagmi';
import { getAccount, readContract, writeContract, waitForTransactionReceipt, getChainId } from '@wagmi/core';
import type { Config } from '@wagmi/core';
import { KraikenAbi } from 'kraiken-lib/abis';
import { type Abi, type Address, type Hash } from 'viem';
import { StakeContract } from '@/contracts/stake';
import { getChain } from '@/config';
import logger from '@/utils/logger';
import { getWalletPublicClient } from '@/services/walletRpc';

interface Contract {
  abi: Abi;
  contractAddress: Address;
}

export const allowance = ref();
export const nonce = ref();
export const name = ref();
export const ubiDue = ref();
export const totalSupply = ref(0n);

// export const HarbContract = await getHarbJson()
export let HarbContract = getHarbJson();

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

  return { abi: KraikenAbi as Abi, contractAddress: chain?.harb } as Contract;
}

export function setHarbContract() {
  HarbContract = getHarbJson();
}

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

  const account = getAccount(config as Config);
  if (!account.address) {
    return 0n;
  }

  const publicClient = getWalletPublicClient();
  if (!publicClient) {
    throw new Error('Wallet public client unavailable');
  }

  const result = (await publicClient.readContract({
    abi: HarbContract.abi,
    address: HarbContract.contractAddress,
    functionName: 'allowance',
    args: [account.address, StakeContract.contractAddress],
  })) as bigint;
  allowance.value = result;
  return result;
}

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

  const account = getAccount(config as Config);
  if (!account.address) {
    return 0n;
  }
  const publicClient = getWalletPublicClient();
  if (!publicClient) {
    throw new Error('Wallet public client unavailable');
  }

  const result = (await publicClient.readContract({
    abi: HarbContract.abi,
    address: HarbContract.contractAddress,
    functionName: 'nonces',
    args: [account.address],
  })) as bigint;
  nonce.value = result;

  return result;
}

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

  const publicClient = getWalletPublicClient();
  if (!publicClient) {
    throw new Error('Wallet public client unavailable');
  }
  const result = (await publicClient.readContract({
    abi: HarbContract.abi,
    address: HarbContract.contractAddress,
    functionName: 'name',
    args: [],
  })) as string;
  name.value = result;

  return result;
}

export async function approve(amount: bigint): Promise<Hash> {
  const account = getAccount(config as Config);
  if (!account.address) {
    throw new Error('no address found');
  }
  const result = await writeContract(config as Config, {
    abi: HarbContract.abi,
    address: HarbContract.contractAddress,
    functionName: 'approve',
    args: [StakeContract.contractAddress, amount],
  });
  await waitForTransactionReceipt(config as Config, {
    hash: result,
  });
  return result;
}

//claim
export async function claimUbi(address: Address): Promise<Hash> {
  const result = await writeContract(config as Config, {
    abi: HarbContract.abi,
    address: HarbContract.contractAddress,
    functionName: 'claimUbi',
    args: [address],
  });

  return result;
}

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

  const result = await readContract(config as Config, {
    abi: HarbContract.abi,
    address: HarbContract.contractAddress,
    functionName: 'totalSupply',
    args: [],
  });
  totalSupply.value = result as bigint;
  return result;
}
