import {
  Account,
  AccountAddress,
  Ed25519PrivateKey,
  Hex,
  Serializer,
  U64,
  AnyRawTransaction,
  AccountAuthenticator,
  AptosConfig,
  APTOS_COIN,
  APTOS_FA,
  Aptos,
  isValidFunctionInfo,
  createObjectAddress,
  AccountAddressInput,
} from "@aptos-labs/ts-sdk";

export const checkCoinToFa = async (
  aptos: Aptos,
  sender: AccountAddressInput,
  exToken: string
): Promise<{
  useCoin: boolean;
  coinType: string;
}> => {
  if (
    !isValidFunctionInfo(exToken) &&
    standardizeMoveTypeString(exToken) !== standardizeMoveTypeString(APTOS_FA)
  ) {
    return {
      useCoin: false,
      coinType: exToken,
    };
  }

  const coinType =
    standardizeMoveTypeString(exToken) === standardizeMoveTypeString(APTOS_FA)
      ? APTOS_COIN
      : exToken;

  const faAddress =
    standardizeMoveTypeString(coinType) === APTOS_COIN
      ? AccountAddress.A
      : createObjectAddress(
          AccountAddress.A,
          standardizeMoveTypeString(coinType)
        );

  const [faBalance] = await aptos.view({
    payload: {
      function: "0x1::primary_fungible_store::balance",
      typeArguments: ["0x1::fungible_asset::Metadata"],
      functionArguments: [sender, faAddress],
    },
  });

  const [coinBalance] = await aptos.view({
    payload: {
      function: "0x1::coin::balance",
      typeArguments: [coinType],
      functionArguments: [sender],
    },
  });

  if (coinBalance === faBalance) {
    return {
      useCoin: false,
      coinType: exToken,
    };
  }

  return {
    useCoin: true,
    coinType: coinType,
  };
};

/**
 * Helper function to standardize Move type string by converting all addresses to short form,
 * including addresses within nested type parameters
 */
function standardizeMoveTypeString(input: string): string {
  // Regular expression to match addresses in the type string, including those within type parameters
  // This regex matches "0x" followed by hex digits, handling both standalone addresses and those within <>
  const addressRegex = /0x[0-9a-fA-F]+/g;

  return input.replace(addressRegex, (match) => {
    // Use AccountAddress to handle the address
    return AccountAddress.from(match, { maxMissingChars: 63 }).toStringShort();
  });
}
