/**
 * Security utility functions for input validation and security checks
 * Adapted for wagmi/viem
 */

import { isAddress, getAddress } from 'viem';
import { ERROR_MESSAGES, VALIDATION, SECURITY } from './constants';

/**
 * Validates Ethereum address with checksum verification
 */
export function validateAddress(address: string): {
  valid: boolean;
  error?: string;
  checksummed?: string;
} {
  if (!address || typeof address !== 'string') {
    return { valid: false, error: ERROR_MESSAGES.INVALID_ADDRESS };
  }

  if (address.length > VALIDATION.ADDRESS_MAX_LENGTH) {
    return { valid: false, error: 'Address exceeds maximum length' };
  }

  if (!isAddress(address)) {
    return { valid: false, error: 'Invalid Ethereum address format' };
  }

  try {
    const checksummed = getAddress(address);
    return { valid: true, checksummed };
  } catch (error: any) {
    return { valid: false, error: error.message || 'Address validation failed' };
  }
}

/**
 * Checks if address is a contract (has code)
 */
export async function isContractAddress(
  address: string,
  publicClient: any // viem PublicClient
): Promise<boolean> {
  try {
    const code = await publicClient.getBytecode({ address: address as `0x${string}` });
    return code !== undefined && code !== '0x' && code !== '0x0';
  } catch {
    return false;
  }
}

/**
 * Validates transaction data field
 */
export function validateTransactionData(data: string): {
  valid: boolean;
  error?: string;
} {
  if (!data) {
    return { valid: true }; // Empty data is valid
  }

  if (typeof data !== 'string') {
    return { valid: false, error: 'Data must be a string' };
  }

  if (!data.startsWith('0x')) {
    return { valid: false, error: 'Data must start with 0x' };
  }

  if (data.length > SECURITY.MAX_TRANSACTION_DATA_LENGTH * 2 + 2) {
    return {
      valid: false,
      error: `Data exceeds maximum length (${SECURITY.MAX_TRANSACTION_DATA_LENGTH} bytes)`,
    };
  }

  if (!/^0x[0-9a-fA-F]*$/.test(data)) {
    return { valid: false, error: 'Data contains invalid hex characters' };
  }

  return { valid: true };
}

/**
 * Rate limiter for admin functions
 */
export class RateLimiter {
  private requests: Map<string, number[]> = new Map();

  checkLimit(identifier: string, maxRequests: number = SECURITY.DEFAULT_RATE_LIMIT_REQUESTS): boolean {
    const now = Date.now();
    const windowStart = now - SECURITY.DEFAULT_RATE_LIMIT_WINDOW_MS;

    if (!this.requests.has(identifier)) {
      this.requests.set(identifier, []);
    }

    const requests = this.requests.get(identifier)!;
    const recentRequests = requests.filter((time) => time > windowStart);

    if (recentRequests.length >= maxRequests) {
      return false;
    }

    recentRequests.push(now);
    this.requests.set(identifier, recentRequests);
    return true;
  }

  clear(identifier?: string): void {
    if (identifier) {
      this.requests.delete(identifier);
    } else {
      this.requests.clear();
    }
  }
}

/**
 * Generate secure ID
 */
export function generateSecureId(): string {
  return `tx_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
}

/**
 * Validate network ID
 */
export function validateNetworkId(networkId: number): boolean {
  // Add supported networks as needed
  const supportedNetworks = [1, 5, 137, 42161, 10, 8453, 100, 56, 250, 43114, 138];
  return supportedNetworks.includes(networkId);
}
