// ═══════════════════════════════════════════════════════════════════════════════
// CRYPTO DEPOSIT VERIFICATION SERVICE
// Verifies ERC-20 token transfers on Celo blockchain
// ═══════════════════════════════════════════════════════════════════════════════

const { ethers } = require('ethers');

// Celo mainnet RPC
const CELO_RPC = 'https://forno.celo.org';
let _provider = null;
function getProvider() {
  if (!_provider) _provider = new ethers.JsonRpcProvider(CELO_RPC);
  return _provider;
}

// Token contracts on Celo
const TOKENS = {
  USDC: {
    address: '0xcebA9300f2b948710d2653dD7B07f33A8B32118C',
    decimals: 6,
    name: 'USDC'
  },
  USDT: {
    address: '0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e',
    decimals: 6,
    name: 'USDT'
  },
  cUSD: {
    address: '0x765DE816845861e75A25fCA122bb6898B8B1282a',
    decimals: 18,
    name: 'cUSD'
  }
};

// ERC-20 Transfer event signature
const TRANSFER_TOPIC = ethers.id('Transfer(address,address,uint256)');

// Treasury address (lowercase for comparison)
const TREASURY = (process.env.TREASURY_ADDRESS || '').toLowerCase();

// Minimum deposit in USD
const MIN_DEPOSIT_USD = 6;

// Bonus percentage
const BONUS_PERCENT = 0;

/**
 * Verify a crypto deposit transaction
 * @param {string} txHash - Transaction hash
 * @param {string} expectedToken - Expected token (USDC, USDT, cUSD)
 * @returns {object} - { success, amount, token, error }
 */
async function verifyDeposit(txHash, expectedToken) {
  try {
    // Validate TX hash format
    if (!txHash || !txHash.match(/^0x[a-fA-F0-9]{64}$/)) {
      return { success: false, error: 'Invalid transaction hash format' };
    }

    // Get token config
    const tokenConfig = TOKENS[expectedToken];
    if (!tokenConfig) {
      return { success: false, error: 'Invalid token selected' };
    }

    // Fetch transaction receipt
    const receipt = await getProvider().getTransactionReceipt(txHash);
    if (!receipt) {
      return { success: false, error: 'Transaction not found. Please wait for confirmations and try again.' };
    }

    // Check if transaction was successful
    if (receipt.status !== 1) {
      return { success: false, error: 'Transaction failed on-chain' };
    }

    // Check confirmations (at least 3)
    const currentBlock = await getProvider().getBlockNumber();
    const confirmations = currentBlock - receipt.blockNumber;
    if (confirmations < 3) {
      return { success: false, error: `Waiting for confirmations (${confirmations}/3). Please try again in a minute.` };
    }

    // Find Transfer event to treasury
    let depositAmount = null;
    let senderAddress = null;
    let foundToken = null;

    for (const log of receipt.logs) {
      // Check if this is a Transfer event
      if (log.topics[0] !== TRANSFER_TOPIC) continue;
      
      // Check if recipient is treasury (topic[2] is 'to' address, padded to 32 bytes)
      const toAddress = '0x' + log.topics[2].slice(26).toLowerCase();
      const fromAddress = '0x' + log.topics[1].slice(26).toLowerCase();
      if (toAddress !== TREASURY) continue;

      // Check which token this is
      const contractAddress = log.address.toLowerCase();
      for (const [symbol, config] of Object.entries(TOKENS)) {
        if (config.address.toLowerCase() === contractAddress) {
          // Decode amount (use formatUnits for precision with 18-decimal tokens)
          const amount = ethers.toBigInt(log.data);
          const amountUsd = parseFloat(ethers.formatUnits(amount, config.decimals));
          
          depositAmount = amountUsd;
          senderAddress = fromAddress;
          foundToken = symbol;
          break;
        }
      }
    }

    if (!depositAmount || !foundToken) {
      return { success: false, error: 'No valid token transfer to treasury found in this transaction' };
    }

    // Verify expected token matches (warning if different)
    if (foundToken !== expectedToken) {
      // Allow it but note the difference
      console.log(`Note: User selected ${expectedToken} but sent ${foundToken}`);
    }

    // Check minimum
    if (depositAmount < MIN_DEPOSIT_USD) {
      return { success: false, error: `Minimum deposit is $${MIN_DEPOSIT_USD}. You sent $${depositAmount.toFixed(2)}` };
    }

    // Calculate bonus
    const bonusUsd = depositAmount * (BONUS_PERCENT / 100);
    const totalUsd = depositAmount + bonusUsd;

    return {
      success: true,
      amount: depositAmount,
      bonus: bonusUsd,
      total: totalUsd,
      token: foundToken,
      txHash: txHash,
      confirmations: confirmations,
      sender: senderAddress
    };

  } catch (error) {
    console.error('Crypto verification error:', error);
    return { success: false, error: 'Verification failed. Please try again or contact support.' };
  }
}

/**
 * Check if TX hash has already been credited
 * @param {object} supabase - Supabase client
 * @param {string} txHash - Transaction hash
 * @returns {boolean} - true if already used
 */
async function isTxHashUsed(supabase, txHash) {
  const { data } = await supabase
    .from('crypto_deposits')
    .select('id')
    .eq('tx_hash', txHash.toLowerCase())
    .single();
  return !!data;
}

/**
 * Record a crypto deposit
 * @param {object} supabase - Supabase client
 * @param {object} params - Deposit parameters
 */
async function recordDeposit(supabase, { userId, txHash, token, amountUsd, bonusUsd, amountVae, senderAddress }) {
  await supabase
    .from('crypto_deposits')
    .insert({
      user_id: userId,
      tx_hash: txHash.toLowerCase(),
      token: token,
      amount_usd: amountUsd,
      bonus_usd: bonusUsd,
      amount_vae: amountVae,
      status: 'completed',
      sender_address: senderAddress,
      verified_at: new Date().toISOString()
    });
}

module.exports = {
  TOKENS,
  MIN_DEPOSIT_USD,
  BONUS_PERCENT,
  TREASURY,
  verifyDeposit,
  isTxHashUsed,
  recordDeposit
};
