import { useDynamicContext, useIsLoggedIn } from "@dynamic-labs/sdk-react-core";
import { isSuiWallet } from "@dynamic-labs/sui";
import { useState, useEffect, useCallback } from "react";
import { Transaction } from "@mysten/sui/transactions";
// Constants for Sui and USDC
const MIST_PER_SUI = 1_000_000_000; // 1 SUI = 1 billion MIST (smallest unit)
const USDC_COIN_TYPE =
  "0xa1ec7fc00a6f40db9693ad1415d0c193ad3906494428cf252621037bd7117e29::usdc::USDC";
const USDC_DECIMALS = 6; // USDC has 6 decimal places
const USDC_PER_UNIT = Math.pow(10, USDC_DECIMALS); // Used to convert between units
export default function Send() {
  // Dynamic wallet integration
  const isLoggedIn = useIsLoggedIn();
  const { primaryWallet } = useDynamicContext();
  // UI state management
  const [isLoading, setIsLoading] = useState(false);
  const [result, setResult] = useState("");
  const [recipientAddress, setRecipientAddress] = useState("");
  const [amount, setAmount] = useState("");
  const [balances, setBalances] = useState({ sui: "0", usdc: "0" });
  const [isBalanceLoading, setIsBalanceLoading] = useState(false);
  const [txSignature, setTxSignature] = useState<string | null>(null);
  const [currentStage, setCurrentStage] = useState<string>("initial");
  // Function to fetch and display user's SUI and USDC balances
  const fetchBalances = useCallback(async () => {
    // Check if wallet is connected and is a Sui wallet
    if (!primaryWallet || !isSuiWallet(primaryWallet)) {
      setBalances({ sui: "0", usdc: "0" });
      return;
    }
    setIsBalanceLoading(true);
    try {
      // Get the Sui client from the wallet
      const walletClient = await primaryWallet.getSuiClient();
      if (!walletClient) return;
      // Fetch both SUI and USDC coins in parallel for better performance
      const [suiCoins, usdcCoins] = await Promise.all([
        walletClient.getCoins({
          owner: primaryWallet.address,
          coinType: "0x2::sui::SUI",
        }),
        walletClient.getCoins({
          owner: primaryWallet.address,
          coinType: USDC_COIN_TYPE,
        }),
      ]);
      // Calculate total balances by summing all coins and converting to human-readable format
      const suiBalance = (
        suiCoins.data.reduce((sum, coin) => sum + Number(coin.balance), 0) /
        MIST_PER_SUI
      ).toFixed(9);
      const usdcBalance = (
        usdcCoins.data.reduce((sum, coin) => sum + Number(coin.balance), 0) /
        USDC_PER_UNIT
      ).toFixed(USDC_DECIMALS);
      setBalances({ sui: suiBalance, usdc: usdcBalance });
    } catch (error) {
      console.error("Error fetching balances:", error);
      setBalances({ sui: "0", usdc: "0" });
    } finally {
      setIsBalanceLoading(false);
    }
  }, [primaryWallet]);
  useEffect(() => {
    if (isLoggedIn && primaryWallet && isSuiWallet(primaryWallet)) {
      fetchBalances();
    } else {
      setBalances({ sui: "0", usdc: "0" });
    }
  }, [isLoggedIn, primaryWallet, fetchBalances]);
  // Main function to send USDC using gasless transactions
  const sendUSDC = async () => {
    // Validate wallet connection
    if (!primaryWallet || !isSuiWallet(primaryWallet)) {
      setResult("Wallet not connected or not a SUI wallet");
      return;
    }
    // Validate user inputs
    if (!recipientAddress || !amount) {
      setResult("Please enter recipient address and amount");
      return;
    }
    try {
      setIsLoading(true);
      setResult("Creating transaction...");
      setCurrentStage("creating");
      // Convert human-readable amount to smallest unit (e.g., 10.5 USDC -> 10,500,000)
      const amountInSmallestUnit = Math.floor(
        parseFloat(amount) * USDC_PER_UNIT
      );
      const walletClient = await primaryWallet.getSuiClient();
      if (!walletClient) {
        throw new Error("Failed to get SUI client from wallet");
      }
      // Get all USDC coins owned by the user
      const ownedCoins = await walletClient.getCoins({
        owner: primaryWallet.address,
        coinType: USDC_COIN_TYPE,
      });
      if (ownedCoins.data.length === 0) {
        throw new Error("No USDC coins found in wallet");
      }
      // Select enough coins to cover the transaction amount
      // This handles cases where the user has multiple USDC coins
      let totalAvailable = 0;
      const coinObjectsToUse = [];
      for (const coin of ownedCoins.data) {
        coinObjectsToUse.push(coin.coinObjectId);
        totalAvailable += Number(coin.balance);
        if (totalAvailable >= amountInSmallestUnit) {
          break;
        }
      }
      // Check if user has enough USDC
      if (totalAvailable < amountInSmallestUnit) {
        throw new Error(
          `Insufficient USDC balance. Available: ${
            totalAvailable / USDC_PER_UNIT
          } USDC`
        );
      }
      // Create a new Sui transaction
      const tx = new Transaction();
      tx.setSender(primaryWallet.address);
      // Handle multiple USDC coins by merging them into one
      // This is necessary because Sui requires specific coin objects for transactions
      let mergedCoin;
      if (coinObjectsToUse.length > 1) {
        const primaryCoin = coinObjectsToUse[0];
        const otherCoins = coinObjectsToUse.slice(1);
        // Merge all coins into the primary coin
        tx.mergeCoins(
          tx.object(primaryCoin),
          otherCoins.map((id) => tx.object(id))
        );
        mergedCoin = tx.object(primaryCoin);
      } else {
        mergedCoin = tx.object(coinObjectsToUse[0]);
      }
      // Split the exact amount needed for the transfer
      const [coinToSend] = tx.splitCoins(mergedCoin, [
        tx.pure.u64(amountInSmallestUnit),
      ]);
      // Transfer the split coin to the recipient
      tx.transferObjects([coinToSend], tx.pure.address(recipientAddress));
      // Build the transaction kind (without gas estimation) for sponsorship
      setCurrentStage("building");
      const kindBytes = await tx.build({
        client: walletClient as any,
        onlyTransactionKind: true,
      });
      // Send the transaction to our API for gas sponsorship
      setResult("Requesting gas sponsorship...");
      setCurrentStage("sponsoring");
      const response = await fetch("/api/gas", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          tx: Array.from(kindBytes),
          senderAddress: primaryWallet.address,
        }),
      });
      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.error || "Failed to sponsor transaction");
      }
      // Get the sponsored transaction data from the API
      const sponsorData = await response.json();
      // Ask the user to sign the sponsored transaction
      setResult("Requesting your signature...");
      setCurrentStage("signing");
      // Convert the sponsored bytes back to a Uint8Array
      const sponsoredBytesArray = new Uint8Array(
        Object.values(sponsorData.sponsoredBytes)
      );
      // Sign the transaction with the user's wallet
      // Try different signing formats in case of compatibility issues
      let signedTransaction;
      try {
        const sponsoredTransaction = Transaction.from(sponsoredBytesArray);
        signedTransaction = await primaryWallet.signTransaction(
          sponsoredTransaction as any
        );
      } catch (signError) {
        signedTransaction = await primaryWallet.signTransaction(
          sponsoredBytesArray as any
        );
      }
      // Execute the transaction on the Sui network
      setResult("Executing transaction...");
      setCurrentStage("executing");
      const executionResult = await walletClient.executeTransactionBlock({
        transactionBlock: sponsoredBytesArray,
        signature: [signedTransaction.signature, sponsorData.sponsorSignature], // Both user and sponsor signatures
        options: {
          showEffects: true,
          showEvents: true,
          showObjectChanges: true,
        },
      });
      // Transaction completed successfully
      setTxSignature(executionResult?.digest || null);
      setResult(`USDC transfer successful! ${executionResult.digest}`);
      setCurrentStage("complete");
      // Wait for transaction confirmation and refresh balances
      await walletClient.waitForTransaction({
        digest: executionResult.digest,
      });
      fetchBalances();
    } catch (error) {
      console.error("Error:", error);
      setTxSignature(null);
      setCurrentStage("error");
      setResult(
        `Error: ${error instanceof Error ? error.message : String(error)}`
      );
    } finally {
      setIsLoading(false);
    }
  };
  return (
    <div>
      <h2>Send USDC on Sui</h2>
      {isLoggedIn && primaryWallet && (
        <div>
          <p>
            Your SUI Balance: {isBalanceLoading ? "Loading..." : `${balances.sui} SUI`}
          </p>
          <p>
            Your USDC Balance: {isBalanceLoading ? "Loading..." : `${balances.usdc} USDC`}
          </p>
          <button onClick={fetchBalances} disabled={isBalanceLoading}>
            Refresh Balance
          </button>
        </div>
      )}
      <div>
        <input
          type="text"
          placeholder="Recipient Address"
          value={recipientAddress}
          onChange={(e) => setRecipientAddress(e.target.value)}
          disabled={isLoading}
        />
        <input
          type="text"
          placeholder="Amount in USDC"
          value={amount}
          onChange={(e) => setAmount(e.target.value)}
          disabled={isLoading}
        />
        <button
          onClick={sendUSDC}
          disabled={
            !isLoggedIn ||
            !primaryWallet ||
            isLoading ||
            !recipientAddress ||
            !amount
          }
        >
          {isLoading ? "Processing..." : "Send USDC"}
        </button>
      </div>
      {result && (
        <div>
          <p>{result}</p>
          {txSignature && (
            <div>
              <p>Signature: {txSignature}</p>
              <a
                href={`https://testnet.suivision.xyz/txblock/${txSignature}`}
                target="_blank"
                rel="noopener noreferrer"
              >
                View on Sui Vision
              </a>
            </div>
          )}
        </div>
      )}
    </div>
  );
}