import {
  Account,
  AccountAddress,
  Ed25519PrivateKey,
  Hex,
  Serializer,
  U64,
  AnyRawTransaction,
  AccountAuthenticator,
  AptosConfig,
  APTOS_COIN,
  APTOS_FA,
  Aptos,
  isValidFunctionInfo,
  createObjectAddress,
  AccountAddressInput,
} from "@aptos-labs/ts-sdk";
import { SettleDiscount } from "./type";
// import {
//   // AccountAddressInput,
//   AccountAuthenticator as AccountAuthenticatorV1,
//   // AnyRawTransaction,
//   // AptosConfig,
//   Aptos as AptosV1,
//   U64 as U64V1,
// } from "aptos-sdk-v1";
import { InputTransactionData } from "@aptos-labs/wallet-adapter-react";

export const signDiscount = (
  discountVerifierPK: string,
  id: string,
  buyerDiscount: number,
  sellerDiscount: number
): SettleDiscount => {
  const discountVerifierKeypair = new Ed25519PrivateKey(discountVerifierPK);
  const signAccount = Account.fromPrivateKey({
    privateKey: discountVerifierKeypair,
  });

  const serializer = new Serializer();
  serializer.serialize(AccountAddress.fromStringStrict(id));
  serializer.serialize(new U64(buyerDiscount));
  serializer.serialize(new U64(sellerDiscount));

  const signature = Array.from(signAccount.sign(serializer.toUint8Array()).toUint8Array());

  return {
    orderId: id,
    buyerDiscount,
    sellerDiscount,
    signature,
  };
};

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,
  };
};

// /* eslint-disable */
// export const convertCoinToFA = async (
//   aptosConfig: AptosConfig,
//   sender: string,
//   exToken: string,
//   signTransaction: (args: {
//     transactionOrPayload: AnyRawTransaction | InputTransactionData;
//     asFeePayer?: boolean;
//   }) => Promise<{
//     authenticator: AccountAuthenticator;
//     rawTransaction: Uint8Array;
//   }>
// ) => {
//   if (
//     !(
//       standardizeMoveTypeString(exToken) ===
//         standardizeMoveTypeString(APTOS_FA) ||
//       standardizeMoveTypeString(exToken) ===
//         standardizeMoveTypeString(APTOS_COIN)
//     )
//   ) {
//     return;
//   }

//   const aptos = new AptosV1(aptosConfig);

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

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

//   if (coinBalance === faBalance) {
//     return;
//   }

//   const transaction = await aptos.transaction.build.scriptComposer({
//     sender: sender,
//     // The builder expects a closure to build up the move call sequence.
//     builder: async (builder) => {
//       // invoke 0x1::coin::withdraw. This function would return a value of a coin type.
//       const coin = await builder.addBatchedCalls({
//         function: "0x1::coin::withdraw",
//         functionArguments: [
//           sender,
//           new U64V1(Number(coinBalance) - Number(faBalance)),
//         ],
//         typeArguments: ["0x1::aptos_coin::AptosCoin"],
//       });

//       // Passing the coin value to the 0x1::coin::coin_to_fungible_asset to convert a coin
//       // into fungible asset.
//       const fungibleAsset = await builder.addBatchedCalls({
//         function: "0x1::coin::coin_to_fungible_asset",
//         // coin[0] represents the first return value from the first call you added.
//         functionArguments: [coin[0]],
//         typeArguments: ["0x1::aptos_coin::AptosCoin"],
//       });

//       // Deposit the fungibleAsset converted from second call.
//       await builder.addBatchedCalls({
//         function: "0x1::primary_fungible_store::deposit",
//         functionArguments: [sender, fungibleAsset[0]],
//         typeArguments: [],
//       });
//       return builder;
//     },
//   });

//   const { authenticator, rawTransaction } = await signTransaction({
//     transactionOrPayload: transaction as unknown as AnyRawTransaction,
//   });

//   const pendingTxn = await aptos.transaction.submit.simple({
//     transaction,
//     senderAuthenticator: authenticator as unknown as AccountAuthenticatorV1,
//   });

//   const response = await aptos.waitForTransaction({
//     transactionHash: pendingTxn.hash,
//   });

//   if (response.success) {
//     throw new Error(`Coin to FA failed: ${response.vm_status}`);
//   }

//   return response;
// };

/**
 * 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();
  });
}
