/**
 * Fabric Event Listener
 * Listens to Hyperledger Fabric chaincode events and triggers EVM bridge operations
 */

import { Gateway, Network, Contract, Wallet } from 'fabric-network';
import { ethers } from 'ethers';

export interface FabricConfig {
    connectionProfile: string;
    walletPath: string;
    identity: string;
    channel: string;
    chaincode: string;
}

export class FabricEventListener {
    private gateway: Gateway;
    private network: Network | null = null;
    private contract: Contract | null = null;
    private evmProvider: ethers.JsonRpcProvider;
    private bridgeContract: ethers.Contract;

    constructor(
        private config: FabricConfig,
        evmRpcUrl: string,
        bridgeAddress: string,
        bridgeAbi: any[]
    ) {
        this.gateway = new Gateway();
        this.evmProvider = new ethers.JsonRpcProvider(evmRpcUrl);
        this.bridgeContract = new ethers.Contract(
            bridgeAddress,
            bridgeAbi,
            this.evmProvider
        );
    }

    /**
     * Connect to Fabric network
     */
    async connect(): Promise<void> {
        const wallet = await this.loadWallet();
        
        await this.gateway.connect(this.config.connectionProfile, {
            wallet,
            identity: this.config.identity,
            discovery: { enabled: true, asLocalhost: false }
        });
        
        this.network = await this.gateway.getNetwork(this.config.channel);
        this.contract = this.network.getContract(this.config.chaincode);
        
        console.log(`Connected to Fabric channel: ${this.config.channel}`);
    }

    /**
     * Listen to bridge events from Fabric
     */
    async listenToBridgeEvents(): Promise<void> {
        if (!this.contract) {
            throw new Error('Not connected to Fabric network');
        }

        // Listen to chaincode events
        await this.contract.addContractListener(
            'bridge-listener',
            'BridgeToEVM',
            async (event: any) => {
                try {
                    console.log('Fabric bridge event received:', event);
                    
                    // Parse event payload
                    const payload = JSON.parse(event.payload.toString());
                    const { assetId, amount, evmRecipient, requestId } = payload;
                    
                    // Confirm on EVM side
                    await this.confirmOnEVM(requestId, assetId, amount, evmRecipient);
                } catch (error) {
                    console.error('Error processing Fabric event:', error);
                }
            }
        );
        
        console.log('Listening to Fabric bridge events...');
    }

    /**
     * Confirm bridge operation on EVM
     */
    private async confirmOnEVM(
        requestId: string,
        assetId: string,
        amount: string,
        recipient: string
    ): Promise<void> {
        // Get signer (operator wallet)
        const signer = new ethers.Wallet(
            process.env.FABRIC_OPERATOR_PRIVATE_KEY!,
            this.evmProvider
        );
        
        const bridgeWithSigner = this.bridgeContract.connect(signer);
        
        // Call confirmFabricOperation
        const tx = await bridgeWithSigner.confirmFabricOperation(
            requestId,
            assetId // Use as fabricTxId
        );
        
        await tx.wait();
        console.log(`Confirmed bridge on EVM: ${tx.hash}`);
    }

    /**
     * Load Fabric wallet
     */
    private async loadWallet(): Promise<Wallet> {
        // Implementation depends on wallet type (file system, in-memory, etc.)
        // This is a placeholder - implement based on your wallet setup
        const { Wallets } = require('fabric-network');
        return await Wallets.newFileSystemWallet(this.config.walletPath);
    }

    /**
     * Disconnect from Fabric
     */
    async disconnect(): Promise<void> {
        if (this.gateway) {
            await this.gateway.disconnect();
        }
    }
}
