/**
 * Blockchain Integration Service
 * Handles cryptocurrency deposits, withdrawals, and real-time conversion
 * Supports: Ethereum, Polygon, Solana, Bitcoin, Arbitrum
 */

import { db } from './db.ts';
import { users, wallets, transactions } from '../drizzle/schema.ts';
import { eq } from 'drizzle-orm';

export type CryptoNetwork = 'ethereum' | 'polygon' | 'solana' | 'bitcoin' | 'arbitrum';
export type CryptoTransactionType = 'deposit' | 'withdrawal' | 'conversion' | 'reward';
export type CryptoTransactionStatus = 'pending' | 'confirmed' | 'failed' | 'cancelled';

/**
 * Crypto wallet interface
 */
export interface CryptoWallet {
  id: string;
  userId: number;
  walletAddress: string;
  network: CryptoNetwork;
  balance: number; // In crypto units
  usdValue: number; // USD equivalent
  isVerified: boolean;
  connectedAt: Date;
  lastSyncedAt: Date;
}

/**
 * Crypto transaction interface
 */
export interface CryptoTransaction {
  id: string;
  userId: number;
  walletAddress: string;
  network: CryptoNetwork;
  type: CryptoTransactionType;
  cryptoAmount: number;
  usdAmount: number;
  exchangeRate: number;
  transactionHash: string;
  status: CryptoTransactionStatus;
  scCredits?: number; // SC credits for deposits
  gasUsed?: number;
  gasFee?: number;
  createdAt: Date;
  completedAt?: Date;
  failureReason?: string;
}

/**
 * Real-time exchange rates
 */
export interface ExchangeRate {
  symbol: string;
  network: CryptoNetwork;
  usdPrice: number;
  lastUpdated: Date;
  change24h: number; // percentage
}

/**
 * Conversion rate cache
 */
const exchangeRateCache: Map<string, ExchangeRate> = new Map();

/**
 * Mock exchange rates (in production, fetch from CoinGecko/Binance API)
 */
const MOCK_EXCHANGE_RATES: Record<CryptoNetwork, number> = {
  ethereum: 3500,
  polygon: 1.2,
  solana: 180,
  bitcoin: 65000,
  arbitrum: 1.5,
};

/**
 * Get real-time exchange rate for crypto to USD
 */
export async function getExchangeRate(network: CryptoNetwork): Promise<ExchangeRate> {
  const cacheKey = `${network}_usd`;
  const cached = exchangeRateCache.get(cacheKey);

  // Return cached rate if less than 5 minutes old
  if (cached && Date.now() - cached.lastUpdated.getTime() < 5 * 60 * 1000) {
    return cached;
  }

  // In production, fetch from CoinGecko or Binance API
  // For now, use mock rates with slight variation
  const baseRate = MOCK_EXCHANGE_RATES[network];
  const variation = (Math.random() - 0.5) * 0.02; // ±1% variation
  const rate: ExchangeRate = {
    symbol: getNetworkSymbol(network),
    network,
    usdPrice: baseRate * (1 + variation),
    lastUpdated: new Date(),
    change24h: (Math.random() - 0.5) * 10, // ±5% mock change
  };

  exchangeRateCache.set(cacheKey, rate);
  return rate;
}

/**
 * Get crypto symbol for network
 */
function getNetworkSymbol(network: CryptoNetwork): string {
  const symbols: Record<CryptoNetwork, string> = {
    ethereum: 'ETH',
    polygon: 'MATIC',
    solana: 'SOL',
    bitcoin: 'BTC',
    arbitrum: 'ARB',
  };
  return symbols[network];
}

/**
 * Convert crypto amount to USD
 */
export async function convertCryptoToUSD(
  amount: number,
  network: CryptoNetwork
): Promise<number> {
  const rate = await getExchangeRate(network);
  return amount * rate.usdPrice;
}

/**
 * Convert USD to crypto amount
 */
export async function convertUSDToCrypto(
  usdAmount: number,
  network: CryptoNetwork
): Promise<number> {
  const rate = await getExchangeRate(network);
  return usdAmount / rate.usdPrice;
}

/**
 * Connect crypto wallet to user account
 */
export async function connectCryptoWallet(
  userId: number,
  walletAddress: string,
  network: CryptoNetwork
): Promise<CryptoWallet> {
  // Verify wallet format
  if (!isValidWalletAddress(walletAddress, network)) {
    throw new Error(`Invalid ${network} wallet address`);
  }

  const wallet: CryptoWallet = {
    id: `wallet_${userId}_${network}_${Date.now()}`,
    userId,
    walletAddress,
    network,
    balance: 0,
    usdValue: 0,
    isVerified: false,
    connectedAt: new Date(),
    lastSyncedAt: new Date(),
  };

  return wallet;
}

/**
 * Verify wallet address format
 */
function isValidWalletAddress(address: string, network: CryptoNetwork): boolean {
  // Basic validation - in production, use proper validation libraries
  const patterns: Record<CryptoNetwork, RegExp> = {
    ethereum: /^0x[a-fA-F0-9]{40}$/,
    polygon: /^0x[a-fA-F0-9]{40}$/,
    solana: /^[1-9A-HJ-NP-Z]{32,34}$/,
    bitcoin: /^(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,62}$/,
    arbitrum: /^0x[a-fA-F0-9]{40}$/,
  };

  return patterns[network].test(address);
}

/**
 * Verify wallet ownership via signature
 */
export async function verifyWalletOwnership(
  walletAddress: string,
  network: CryptoNetwork,
  signature: string,
  message: string
): Promise<boolean> {
  // In production, use ethers.js or similar to verify signature
  // This is a placeholder implementation
  return signature.length > 0 && message.length > 0;
}

/**
 * Create crypto deposit transaction
 */
export async function createCryptoDeposit(
  userId: number,
  walletAddress: string,
  network: CryptoNetwork,
  cryptoAmount: number,
  transactionHash: string
): Promise<CryptoTransaction> {
  const usdAmount = await convertCryptoToUSD(cryptoAmount, network);
  const rate = await getExchangeRate(network);

  // Convert USD to SC credits (1 USD = 1 SC for now)
  const scCredits = Math.floor(usdAmount);

  const transaction: CryptoTransaction = {
    id: `tx_deposit_${userId}_${Date.now()}`,
    userId,
    walletAddress,
    network,
    type: 'deposit',
    cryptoAmount,
    usdAmount,
    exchangeRate: rate.usdPrice,
    transactionHash,
    status: 'pending',
    scCredits,
    createdAt: new Date(),
  };

  return transaction;
}

/**
 * Create crypto withdrawal transaction
 */
export async function createCryptoWithdrawal(
  userId: number,
  walletAddress: string,
  network: CryptoNetwork,
  scAmount: number,
  transactionHash: string
): Promise<CryptoTransaction> {
  // Convert SC to USD (1 SC = 1 USD)
  const usdAmount = scAmount;

  // Convert USD to crypto
  const cryptoAmount = await convertUSDToCrypto(usdAmount, network);
  const rate = await getExchangeRate(network);

  const transaction: CryptoTransaction = {
    id: `tx_withdrawal_${userId}_${Date.now()}`,
    userId,
    walletAddress,
    network,
    type: 'withdrawal',
    cryptoAmount,
    usdAmount,
    exchangeRate: rate.usdPrice,
    transactionHash,
    status: 'pending',
    createdAt: new Date(),
  };

  return transaction;
}

/**
 * Confirm crypto transaction
 */
export async function confirmCryptoTransaction(
  transaction: CryptoTransaction,
  gasUsed?: number,
  gasFee?: number
): Promise<void> {
  transaction.status = 'confirmed';
  transaction.completedAt = new Date();
  if (gasUsed) transaction.gasUsed = gasUsed;
  if (gasFee) transaction.gasFee = gasFee;

  // If deposit, credit user's SC wallet
  if (transaction.type === 'deposit' && transaction.scCredits) {
    const userWallet = await db
      .select()
      .from(wallets)
      .where(eq(wallets.userId, transaction.userId))
      .limit(1);

    if (userWallet.length > 0) {
      const newBalance =
        parseFloat(userWallet[0].scBalance.toString()) + transaction.scCredits;
      await db
        .update(wallets)
        .set({ scBalance: newBalance.toString() })
        .where(eq(wallets.userId, transaction.userId));
    }
  }

  // If withdrawal, debit user's SC wallet
  if (transaction.type === 'withdrawal') {
    const userWallet = await db
      .select()
      .from(wallets)
      .where(eq(wallets.userId, transaction.userId))
      .limit(1);

    if (userWallet.length > 0) {
      const newBalance = parseFloat(userWallet[0].scBalance.toString()) - transaction.usdAmount;
      if (newBalance >= 0) {
        await db
          .update(wallets)
          .set({ scBalance: newBalance.toString() })
          .where(eq(wallets.userId, transaction.userId));
      }
    }
  }
}

/**
 * Fail crypto transaction
 */
export async function failCryptoTransaction(
  transaction: CryptoTransaction,
  reason: string
): Promise<void> {
  transaction.status = 'failed';
  transaction.failureReason = reason;
  transaction.completedAt = new Date();
}

/**
 * Get user's crypto wallets
 */
export async function getUserCryptoWallets(userId: number): Promise<CryptoWallet[]> {
  // In production, fetch from database
  // For now, return empty array
  return [];
}

/**
 * Get user's crypto transaction history
 */
export async function getUserCryptoTransactions(
  userId: number,
  limit: number = 50
): Promise<CryptoTransaction[]> {
  // In production, fetch from database
  // For now, return empty array
  return [];
}

/**
 * Calculate total crypto portfolio value in USD
 */
export async function calculatePortfolioValue(wallets: CryptoWallet[]): Promise<number> {
  let totalValue = 0;

  for (const wallet of wallets) {
    const usdValue = await convertCryptoToUSD(wallet.balance, wallet.network);
    totalValue += usdValue;
  }

  return totalValue;
}

/**
 * Get KYC verification status for crypto
 */
export async function getKYCStatusForCrypto(userId: number): Promise<{
  isVerified: boolean;
  level: 'unverified' | 'basic' | 'intermediate' | 'advanced';
  cryptoLimit: number; // USD
  dailyLimit: number; // USD
}> {
  // In production, fetch from KYC database
  return {
    isVerified: false,
    level: 'unverified',
    cryptoLimit: 0,
    dailyLimit: 0,
  };
}

/**
 * Validate crypto deposit amount
 */
export async function validateCryptoDeposit(
  userId: number,
  usdAmount: number
): Promise<{ valid: boolean; error?: string }> {
  // Check minimum deposit (100 SC = $100)
  if (usdAmount < 100) {
    return { valid: false, error: 'Minimum deposit is $100 USD' };
  }

  // Check KYC verification
  const kyc = await getKYCStatusForCrypto(userId);
  if (!kyc.isVerified) {
    return { valid: false, error: 'KYC verification required for crypto deposits' };
  }

  // Check daily limit
  if (usdAmount > kyc.dailyLimit) {
    return { valid: false, error: `Daily limit is $${kyc.dailyLimit}` };
  }

  return { valid: true };
}

/**
 * Validate crypto withdrawal amount
 */
export async function validateCryptoWithdrawal(
  userId: number,
  scAmount: number
): Promise<{ valid: boolean; error?: string }> {
  // Check minimum withdrawal (100 SC)
  if (scAmount < 100) {
    return { valid: false, error: 'Minimum withdrawal is 100 SC' };
  }

  // Check KYC verification
  const kyc = await getKYCStatusForCrypto(userId);
  if (!kyc.isVerified) {
    return { valid: false, error: 'KYC verification required for crypto withdrawals' };
  }

  // Check user balance
  const userWallet = await db
    .select()
    .from(wallets)
    .where(eq(wallets.userId, userId))
    .limit(1);

  if (userWallet.length === 0) {
    return { valid: false, error: 'User wallet not found' };
  }

  const balance = parseFloat(userWallet[0].scBalance.toString());
  if (balance < scAmount) {
    return { valid: false, error: 'Insufficient SC balance' };
  }

  return { valid: true };
}

/**
 * Get supported networks
 */
export function getSupportedNetworks(): CryptoNetwork[] {
  return ['ethereum', 'polygon', 'solana', 'bitcoin', 'arbitrum'];
}

/**
 * Get network info
 */
export function getNetworkInfo(network: CryptoNetwork): {
  name: string;
  symbol: string;
  minDeposit: number;
  minWithdrawal: number;
  gasFeeEstimate: number;
} {
  const info: Record<
    CryptoNetwork,
    {
      name: string;
      symbol: string;
      minDeposit: number;
      minWithdrawal: number;
      gasFeeEstimate: number;
    }
  > = {
    ethereum: {
      name: 'Ethereum',
      symbol: 'ETH',
      minDeposit: 0.05,
      minWithdrawal: 0.05,
      gasFeeEstimate: 0.01,
    },
    polygon: {
      name: 'Polygon',
      symbol: 'MATIC',
      minDeposit: 50,
      minWithdrawal: 50,
      gasFeeEstimate: 1,
    },
    solana: {
      name: 'Solana',
      symbol: 'SOL',
      minDeposit: 1,
      minWithdrawal: 1,
      gasFeeEstimate: 0.00025,
    },
    bitcoin: {
      name: 'Bitcoin',
      symbol: 'BTC',
      minDeposit: 0.001,
      minWithdrawal: 0.001,
      gasFeeEstimate: 0.0001,
    },
    arbitrum: {
      name: 'Arbitrum',
      symbol: 'ARB',
      minDeposit: 100,
      minWithdrawal: 100,
      gasFeeEstimate: 0.5,
    },
  };

  return info[network];
}
