import { Keypair, PublicKey, Connection } from "@solana/web3.js";
import { EuEtsWeb3 } from "../../target/types/eu_ets_web3";
import { Program } from "@coral-xyz/anchor";
import { TOKEN_PROGRAM_ID, mintTo } from "@solana/spl-token";
import * as anchor from "@coral-xyz/anchor";

/**
 * Fetches the next order ID from the on-chain marketConfig account
 * and returns both the numeric orderId and its 8-byte little-endian Buffer.
 *
 * Usage:
 *   const { orderId, orderIdBytes } = await getNextOrderIdBytes(program, marketPda);
 *   const [orderPda] = PublicKey.findProgramAddressSync(
 *     [Buffer.from("order"), marketPda.toBuffer(), companyAdmin.publicKey.toBuffer(), orderIdBytes],
 *     program.programId
 *   );
 */
export async function getNextOrderIdBytes(
  program: Program<EuEtsWeb3>,
  marketPda: PublicKey
): Promise<{ orderId: number; orderIdBytes: Buffer }> {
  const marketAccount = await program.account.marketConfig.fetch(marketPda);
  const orderId = marketAccount.nextOrderId.toNumber();

  const orderIdBytes = Buffer.alloc(8);
  orderIdBytes.writeUInt32LE(orderId, 0);

  return { orderId, orderIdBytes };
}


/**
 * Helper function to deposit USDC from a company admin's ATA to their vault
 * 
 * @param program - The Anchor program instance
 * @param connection - The Solana connection
 * @param companyPda - The company's PDA
 * @param companyUsdcVault - The company's USDC vault
 * @param companyAdminUsdcAta - The company admin's USDC associated token account
 * @param companyAdmin - The company admin keypair
 * @param amount - Amount of USDC to deposit (in base units, 6 decimals)
 */
export async function depositUsdcToVault(
  program: Program<EuEtsWeb3>,
  connection: Connection,
  companyPda: PublicKey,
  companyUsdcVault: PublicKey,
  companyAdminUsdcAta: PublicKey,
  companyAdmin: Keypair,
  amount: number
): Promise<void> {
  const signature = await program.methods
    .depositUsdc(new anchor.BN(amount))
    .accounts({
      company: companyPda,
      companyUsdcVault: companyUsdcVault,
      companyAdminUsdcAta: companyAdminUsdcAta,
      companyAdmin: companyAdmin.publicKey,
      tokenProgram: TOKEN_PROGRAM_ID,
    })
    .signers([companyAdmin])
    .rpc();

  // Wait for finalized confirmation
  await connection.confirmTransaction(signature, "finalized");

  console.log(`✓ Deposited ${amount / 1_000_000} USDC to vault (signature: ${signature})`);
}

/**
 * Helper function to mint USDC to a company admin's ATA and then deposit to vault
 * Useful when the admin's ATA doesn't have enough USDC
 * 
 * @param program - The Anchor program instance
 * @param connection - The Solana connection
 * @param usdcMint - The USDC mint address
 * @param globalAdmin - The global admin keypair (mint authority)
 * @param companyPda - The company's PDA
 * @param companyUsdcVault - The company's USDC vault
 * @param companyAdminUsdcAta - The company admin's USDC associated token account
 * @param companyAdmin - The company admin keypair
 * @param mintAmount - Amount of USDC to mint (in base units, 6 decimals)
 * @param depositAmount - Amount of USDC to deposit to vault (in base units, 6 decimals)
 */
export async function mintAndDepositUsdc(
  program: Program<EuEtsWeb3>,
  connection: Connection,
  usdcMint: PublicKey,
  globalAdmin: Keypair,
  companyPda: PublicKey,
  companyUsdcVault: PublicKey,
  companyAdminUsdcAta: PublicKey,
  companyAdmin: Keypair,
  mintAmount: number,
  depositAmount: number
): Promise<void> {
  console.log(`  Minting ${mintAmount / 1_000_000} USDC to admin's ATA...`);

  // First mint USDC to the admin's ATA with finalized confirmation
  const mintSignature = await mintTo(
    connection,
    globalAdmin,
    usdcMint,
    companyAdminUsdcAta,
    globalAdmin,
    mintAmount,
    [],
    { commitment: "finalized" }
  );

  // Extra wait for finalized confirmation to be absolutely sure
  await connection.confirmTransaction(mintSignature, "finalized");

  console.log(`  ✓ Minted ${mintAmount / 1_000_000} USDC to admin's ATA (signature: ${mintSignature})`);

  // Add a longer delay to ensure the mint is fully processed and visible
  await new Promise(resolve => setTimeout(resolve, 15000));

  // Then deposit to vault (this function already has finalized confirmation)
  console.log(`  Depositing ${depositAmount / 1_000_000} USDC to vault...`);
  await depositUsdcToVault(
    program,
    connection,
    companyPda,
    companyUsdcVault,
    companyAdminUsdcAta,
    companyAdmin,
    depositAmount
  );
}

/**
 * Quick helper to ensure a company has sufficient USDC in their vault
 * Mints and deposits additional USDC if needed
 * 
 * @param program - The Anchor program instance
 * @param connection - The Solana connection
 * @param usdcMint - The USDC mint address
 * @param globalAdmin - The global admin keypair (mint authority)
 * @param companyPda - The company's PDA
 * @param companyUsdcVault - The company's USDC vault
 * @param companyAdminUsdcAta - The company admin's USDC associated token account
 * @param companyAdmin - The company admin keypair
 * @param topUpAmount - Amount of USDC to add (in base units, 6 decimals). Default: 1000 USDC
 */
export async function ensureSufficientUsdc(
  program: Program<EuEtsWeb3>,
  connection: Connection,
  usdcMint: PublicKey,
  globalAdmin: Keypair,
  companyPda: PublicKey,
  companyUsdcVault: PublicKey,
  companyAdminUsdcAta: PublicKey,
  companyAdmin: Keypair,
  topUpAmount: number = 1_000_000_000 // Default 1000 USDC
): Promise<void> {
  console.log(`⚠️  Topping up ${topUpAmount / 1_000_000} USDC...`);

  await mintAndDepositUsdc(
    program,
    connection,
    usdcMint,
    globalAdmin,
    companyPda,
    companyUsdcVault,
    companyAdminUsdcAta,
    companyAdmin,
    topUpAmount,
    topUpAmount
  );

  console.log(`✓ Successfully topped up ${topUpAmount / 1_000_000} USDC`);
}
