import { ref, onMounted, reactive, computed } from 'vue';
import { type ComputedRef } from 'vue';
import { config } from '@/wagmi';
import { decodeEventLog, type Hex, type DecodeEventLogReturnType, type TypedDataDefinition } from 'viem';
import { getAccount, signTypedData, waitForTransactionReceipt, type Config } from '@wagmi/core';
import { HarbContract } from '@/contracts/harb';
import { StakeContract, permitAndSnatch, minStake } from '@/contracts/stake';
import { getNonce, nonce, getName } from '@/contracts/harb';
import { useWallet } from '@/composables/useWallet';
import { createPermitObject, getSignatureRSV } from '@/utils/blockchain';
import { weiToNumber, compactNumber } from 'kraiken-lib/format';
import { getTaxRateOptionByIndex } from '@/composables/useAdjustTaxRates';
import { useContractToast } from './useContractToast';
import { trackStakeCreated } from '@harb/analytics';
const wallet = useWallet();
const contractToast = useContractToast();
const wagmiConfig: Config = config;

enum StakeState {
  NoBalance = 'NoBalance',
  StakeAble = 'StakeAble',
  SignTransaction = 'SignTransaction',
  Waiting = 'Waiting',
  NotEnoughApproval = 'NotEnoughApproval',
}

interface PositionCreatedArgs {
  creationTime: number;
  owner: Hex;
  harbergDeposit: bigint;
  positionId: bigint;
  share: bigint;
  taxRate: number;
}

// const state = ref<StakeState>(StakeState.NoBalance);

export function useStake() {
  const stakingAmountRaw = ref();
  const stakingAmountShares = ref();
  const loading = ref(false);
  const waiting = ref(false);

  onMounted(async () => {});

  const state: ComputedRef<StakeState> = computed(() => {
    const balance = wallet.balance.value;
    if (loading.value) {
      return StakeState.SignTransaction;
    } else if (minStake.value > balance || stakingAmount.value > balance) {
      return StakeState.NoBalance;
    } else if (waiting.value) {
      return StakeState.Waiting;
    } else {
      return StakeState.StakeAble;
    }
  });

  const stakingAmount = computed({
    // getter
    get() {
      return stakingAmountRaw.value || minStake.value;
    },
    // setter
    set(newValue) {
      stakingAmountRaw.value = newValue;
    },
  });

  const stakingAmountNumber = computed({
    // getter
    get() {
      return weiToNumber(stakingAmount.value, 18);
    },
    // setter
    set(newValue) {
      stakingAmount.value = BigInt(newValue * 10 ** 18);
    },
  });

  // const stakingAmountNumber = computed(() => return staking)

  async function snatch(stakingAmount: bigint, taxRateIndex: number, positions: Array<bigint> = []) {
    const account = getAccount(wagmiConfig);
    const taxRateOption = getTaxRateOptionByIndex(taxRateIndex);
    if (!taxRateOption) {
      throw new Error(`Invalid tax rate index: ${taxRateIndex}`);
    }

    try {
      const assets: bigint = stakingAmount;
      // await snatchService(assets, receiver, taxRate, []);
      // assets: BigInt, receiver: Address, taxRate: Number, positionsToSnatch: Array<BigInt>
      const deadline = BigInt(Date.now()) / 1000n + 1200n;

      const name = await getName();

      const { types, message, domain, primaryType } = createPermitObject(
        HarbContract.contractAddress,
        account.address!,
        StakeContract.contractAddress,
        nonce.value,
        deadline,
        assets,
        account.chainId!,
        name
      );
      const typedData: TypedDataDefinition = {
        domain,
        message,
        primaryType,
        types,
      };

      const signature = await signTypedData(wagmiConfig, typedData);
      const { r, s, v } = getSignatureRSV(signature);
      loading.value = true;
      const hash = await permitAndSnatch(assets, account.address!, taxRateOption.index, positions, deadline, v, r, s);
      loading.value = false;
      waiting.value = true;
      const data = await waitForTransactionReceipt(wagmiConfig, {
        hash: hash,
      });

      const topics = decodeEventLog({
        abi: StakeContract.abi,
        data: data.logs[3].data,
        topics: data.logs[3].topics,
      }) as DecodeEventLogReturnType & { args: PositionCreatedArgs };
      const eventArgs: PositionCreatedArgs = topics.args;

      const amount = compactNumber(weiToNumber(eventArgs.harbergDeposit, wallet.balance.decimals));
      trackStakeCreated();
      contractToast.showSuccessToast(amount, 'Success!', 'You Staked', 'Check your positions on the<br /> Staker Dashboard', '$KRK');

      waiting.value = false;
      await getNonce();
    } catch (error) {
      const message = error instanceof Error ? error.name : 'Transaction failed';
      contractToast.showFailToast(message);
    } finally {
      loading.value = false;
      waiting.value = false;
    }
  }

  return reactive({ stakingAmount, stakingAmountShares, stakingAmountNumber, state, snatch });
}
