/**
 * Blockchain Service
 * Enterprise Ethereum Alliance (EEA) blockchain integration
 * For identity verification, resource tracking, and compliance
 */

import { logger } from '../lib/logger.js'
import { ethers } from 'ethers'

export interface BlockchainConfig {
  rpcUrl?: string
  networkId?: string
  contractAddress?: string
  privateKey?: string
  enabled: boolean
}

export interface IdentityVerificationResult {
  verified: boolean
  address?: string
  timestamp?: Date
  error?: string
}

class BlockchainService {
  private config: BlockchainConfig
  private initialized: boolean = false
  private provider: ethers.JsonRpcProvider | null = null
  private wallet: ethers.Wallet | null = null
  private identityContract: ethers.Contract | null = null

  constructor() {
    this.config = {
      enabled: process.env.BLOCKCHAIN_ENABLED === 'true',
      rpcUrl: process.env.BLOCKCHAIN_RPC_URL,
      networkId: process.env.BLOCKCHAIN_NETWORK_ID,
      contractAddress: process.env.BLOCKCHAIN_IDENTITY_CONTRACT_ADDRESS,
      privateKey: process.env.BLOCKCHAIN_PRIVATE_KEY,
    }
  }

  /**
   * Initialize blockchain service
   */
  async initialize(): Promise<void> {
    if (!this.config.enabled) {
      logger.info('Blockchain service is disabled')
      this.initialized = true
      return
    }

    if (!this.config.rpcUrl) {
      logger.warn('Blockchain RPC URL not configured, service will operate in mock mode')
      this.initialized = true
      return
    }

    try {
      if (!this.config.rpcUrl) {
        throw new Error('Blockchain RPC URL is required when blockchain is enabled')
      }

      // Initialize Ethers.js provider
      this.provider = new ethers.JsonRpcProvider(this.config.rpcUrl)

      // Initialize wallet if private key is provided
      if (this.config.privateKey) {
        this.wallet = new ethers.Wallet(this.config.privateKey, this.provider)
        logger.info('Blockchain wallet initialized', {
          address: this.wallet.address,
        })
      }

      // Load identity contract if address is provided
      if (this.config.contractAddress) {
        // Basic ABI for identity verification contract
        // In production, this would be loaded from contract artifacts
        const identityABI = [
          'function isVerified(address user) external view returns (bool)',
          'function registerIdentity(address user, bytes32 userIdHash) external returns (bool)',
          'function revokeIdentity(address user) external returns (bool)',
        ]

        const contractAddress = this.config.contractAddress
        const signer = this.wallet || this.provider

        this.identityContract = new ethers.Contract(
          contractAddress,
          identityABI,
          signer
        )

        // Verify contract is deployed
        const code = await this.provider.getCode(contractAddress)
        if (code === '0x') {
          throw new Error(`Contract not deployed at address ${contractAddress}`)
        }

        logger.info('Identity contract loaded', { contractAddress })
      }
      
      logger.info('Blockchain service initialized', {
        networkId: this.config.networkId,
        contractAddress: this.config.contractAddress,
        providerUrl: this.config.rpcUrl,
      })
      
      this.initialized = true
    } catch (error) {
      logger.error('Failed to initialize blockchain service', { error })
      throw error
    }
  }

  /**
   * Verify blockchain identity
   * Checks if a user's blockchain address is registered and verified
   */
  async verifyIdentity(
    userId: string,
    blockchainAddress: string
  ): Promise<IdentityVerificationResult> {
    if (!this.initialized) {
      await this.initialize()
    }

    if (!this.config.enabled) {
      logger.info('Blockchain verification skipped (disabled)', { userId, blockchainAddress })
      return {
        verified: true, // Allow when blockchain is disabled
        address: blockchainAddress,
        timestamp: new Date(),
      }
    }

    if (!blockchainAddress || !blockchainAddress.match(/^0x[a-fA-F0-9]{40}$/)) {
      logger.warn('Invalid blockchain address format', { userId, blockchainAddress })
      return {
        verified: false,
        address: blockchainAddress,
        error: 'Invalid blockchain address format',
      }
    }

    try {
      if (!this.provider) {
        throw new Error('Blockchain provider not initialized')
      }

      if (!this.identityContract) {
        // If contract is not configured, verify address format only
        logger.info('Blockchain identity verification (no contract)', {
          userId,
          blockchainAddress,
        })
        return {
          verified: true,
          address: blockchainAddress,
          timestamp: new Date(),
        }
      }

      // Query identity contract for verification status
      const isVerified = await this.identityContract.isVerified(blockchainAddress) as boolean
      
      logger.info('Blockchain identity verification', {
        userId,
        blockchainAddress,
        verified: isVerified,
        networkId: this.config.networkId,
      })
      
      return {
        verified: isVerified,
        address: blockchainAddress,
        timestamp: new Date(),
        ...(isVerified ? {} : { error: 'Address not verified on blockchain' }),
      }
    } catch (error) {
      logger.error('Blockchain verification failed', { userId, blockchainAddress, error })
      return {
        verified: false,
        address: blockchainAddress,
        error: error instanceof Error ? error.message : 'Unknown error',
      }
    }
  }

  /**
   * Register identity on blockchain
   * Registers a user's blockchain address in the identity contract
   */
  async registerIdentity(
    userId: string,
    blockchainAddress: string,
    metadata?: Record<string, unknown>
  ): Promise<{ success: boolean; transactionHash?: string; error?: string }> {
    if (!this.initialized) {
      await this.initialize()
    }

    if (!this.config.enabled) {
      logger.info('Blockchain registration skipped (disabled)', { userId, blockchainAddress })
      return { success: true }
    }

    try {
      if (!this.provider) {
        throw new Error('Blockchain provider not initialized')
      }

      if (!this.identityContract) {
        throw new Error('Identity contract not configured')
      }

      if (!this.wallet) {
        throw new Error('Blockchain wallet not configured (private key required for registration)')
      }

      // Create hash of userId for on-chain storage
      const userIdHash = ethers.id(userId)

      // Prepare and send transaction
      logger.info('Registering identity on blockchain', {
        userId,
        blockchainAddress,
        userIdHash,
      })

      const tx = await this.identityContract.registerIdentity(blockchainAddress, userIdHash)
      
      logger.info('Blockchain registration transaction sent', {
        transactionHash: tx.hash,
        userId,
        blockchainAddress,
      })

      // Wait for transaction confirmation
      const receipt = await tx.wait()
      
      if (!receipt) {
        throw new Error('Transaction receipt not received')
      }

      logger.info('Blockchain identity registered', {
        transactionHash: receipt.hash,
        blockNumber: receipt.blockNumber,
        userId,
        blockchainAddress,
      })

      return {
        success: true,
        transactionHash: receipt.hash,
      }
    } catch (error) {
      logger.error('Blockchain registration failed', { userId, blockchainAddress, error })
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error',
      }
    }
  }

  /**
   * Check if blockchain service is enabled
   */
  isEnabled(): boolean {
    return this.config.enabled
  }

  /**
   * Check if blockchain service is initialized
   */
  isInitialized(): boolean {
    return this.initialized
  }
}

// Singleton instance
export const blockchainService = new BlockchainService()
