/**
 * @file settlement-generator.ts
 * @notice Settlement file generator combining blockchain and banking data
 */

import { ethers } from 'ethers';
import { TokenizationWorkflow, SettlementFile } from './tokenization-workflow';

export interface SettlementRequest {
    besuTxHash: string;
    fabricTxHash?: string;
    swiftReference?: string;
    target2Code?: string;
    regulatoryData?: Record<string, any>;
    identityData?: {
        did?: string;
        vcType?: string;
        claims?: Record<string, any>;
    };
}

export class SettlementGenerator {
    private provider: ethers.Provider;
    private fireflyApiUrl: string;

    constructor(rpcUrl: string, fireflyApiUrl: string) {
        this.provider = new ethers.JsonRpcProvider(rpcUrl);
        this.fireflyApiUrl = fireflyApiUrl;
    }

    /**
     * Generate settlement file from transaction
     */
    async generateSettlementFile(request: SettlementRequest): Promise<SettlementFile> {
        // Get blockchain transaction data
        const tx = await this.provider.getTransaction(request.besuTxHash);
        if (!tx) {
            throw new Error('Transaction not found');
        }

        const receipt = await this.provider.getTransactionReceipt(request.besuTxHash);
        if (!receipt) {
            throw new Error('Transaction receipt not found');
        }

        // Get token transfer details from event logs
        const transferEvent = this.parseTransferEvent(receipt.logs);

        // Generate traditional banking data
        const traditional = await this.generateTraditionalBankingData(request, tx, receipt);

        return {
            blockchain: {
                hash: tx.hash,
                from: tx.from,
                to: tx.to || transferEvent?.to || '',
                value: tx.value.toString(),
                gas: tx.gasLimit.toString(),
                gasPrice: tx.gasPrice?.toString() || '0',
                nonce: tx.nonce.toString(),
                blockNumber: receipt.blockNumber.toString(),
                transactionIndex: receipt.index.toString(),
                input: tx.data,
                chainId: tx.chainId?.toString() || '138',
                usdtErc20: transferEvent ? 'token' : 'native'
            },
            traditional
        };
    }

    /**
     * Parse ERC-20 transfer event from logs
     */
    private parseTransferEvent(logs: ethers.Log[]): { to: string; value: string } | null {
        // ERC-20 Transfer event signature: Transfer(address,address,uint256)
        const transferTopic = ethers.id('Transfer(address,address,uint256)');

        for (const log of logs) {
            if (log.topics[0] === transferTopic && log.topics.length === 3) {
                const to = ethers.getAddress('0x' + log.topics[2].slice(26));
                const value = BigInt(log.data).toString();
                return { to, value };
            }
        }

        return null;
    }

    /**
     * Generate traditional banking data
     */
    private async generateTraditionalBankingData(
        request: SettlementRequest,
        tx: ethers.TransactionResponse,
        receipt: ethers.TransactionReceipt
    ): Promise<SettlementFile['traditional']> {
        // Get SWIFT reference (generate if not provided)
        const swiftReference = request.swiftReference || this.generateSwiftReference();

        // Get TARGET2 code (generate if not provided)
        const target2Code = request.target2Code || this.generateTarget2Code();

        // Get identity data from Indy (if provided)
        let identityCode: string | undefined;
        let permitCode: string | undefined;
        let accessCode: string | undefined;

        if (request.identityData) {
            identityCode = await this.getIdentityCode(request.identityData);
            permitCode = await this.getPermitCode(request.identityData);
            accessCode = await this.getAccessCode(request.identityData);
        }

        // Get regulatory flags
        const regulatoryFlags = request.regulatoryData || {};

        return {
            swiftReference,
            target2Code,
            regulatoryFlags,
            identityCode,
            permitCode,
            accessCode
        };
    }

    /**
     * Generate SWIFT reference
     */
    private generateSwiftReference(): string {
        const timestamp = Date.now();
        const random = Math.random().toString(36).substr(2, 9).toUpperCase();
        return `SWIFT-${timestamp}-${random}`;
    }

    /**
     * Generate TARGET2 code
     */
    private generateTarget2Code(): string {
        return `T2-${Date.now()}`;
    }

    /**
     * Get identity code from Indy credentials
     */
    private async getIdentityCode(identityData: SettlementRequest['identityData']): Promise<string> {
        if (!identityData?.did) {
            return '42Q GB DD GB 42FOP 36F'; // Default format
        }

        // In production, query Indy ledger for credential
        // For now, return formatted DID
        return identityData.did;
    }

    /**
     * Get permit code from Indy credentials
     */
    private async getPermitCode(identityData: SettlementRequest['identityData']): Promise<string> {
        if (!identityData?.claims?.permitCode) {
            return `PERMIT-${Date.now()}`;
        }

        return identityData.claims.permitCode;
    }

    /**
     * Get access code from Indy credentials
     */
    private async getAccessCode(identityData: SettlementRequest['identityData']): Promise<string> {
        if (!identityData?.claims?.accessCode) {
            return `ACCESS-${Date.now()}`;
        }

        return identityData.claims.accessCode;
    }

    /**
     * Generate ISO-20022 message from settlement file
     */
    async generateISO20022Message(settlementFile: SettlementFile): Promise<string> {
        // Generate pacs.008 (Payment Initiation) message
        const iso20022 = {
            Document: {
                '@xmlns': 'urn:iso:std:iso:20022:tech:xsd:pacs.008.001.10',
                '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
                'FIToFICstmrCdtTrf': {
                    'GrpHdr': {
                        'MsgId': settlementFile.traditional.swiftReference,
                        'CreDtTm': new Date().toISOString(),
                        'NbOfTxs': '1',
                        'CtrlSum': settlementFile.blockchain.value
                    },
                    'CdtTrfTxInf': {
                        'PmtId': {
                            'EndToEndId': settlementFile.blockchain.hash,
                            'TxId': settlementFile.blockchain.hash
                        },
                        'PmtTpInf': {
                            'SvcLvl': {
                                'Cd': 'SEPA'
                            }
                        },
                        'IntrBkSttlmAmt': {
                            '@Ccy': 'EUR',
                            '#text': settlementFile.blockchain.value
                        },
                        'ChrgBr': 'DEBT',
                        'Dbtr': {
                            'Nm': settlementFile.blockchain.from
                        },
                        'DbtrAcct': {
                            'Id': {
                                'IBAN': settlementFile.blockchain.from
                            }
                        },
                        'Cdtr': {
                            'Nm': settlementFile.blockchain.to
                        },
                        'CdtrAcct': {
                            'Id': {
                                'IBAN': settlementFile.blockchain.to
                            }
                        }
                    }
                }
            }
        };

        // Convert to XML (simplified - use proper XML library in production)
        return JSON.stringify(iso20022, null, 2);
    }

    /**
     * Generate SWIFT FIN message (MT103)
     */
    async generateSWIFTMessage(settlementFile: SettlementFile): Promise<string> {
        // MT103 format
        const swift = {
            'Basic Header': {
                'Application Identifier': 'F',
                'Service Identifier': '01',
                'LT Address': 'DBISGB2LXXXX',
                'Session Number': '0000',
                'Sequence Number': '000000'
            },
            'Application Header': {
                'Input/Output': 'I',
                'Message Type': '103',
                'Receiver Address': settlementFile.blockchain.to,
                'Message Priority': 'N',
                'Delivery Monitoring': '1',
                'Obsolescence Period': '003'
            },
            'User Header': {
                'Service Identifier': '103',
                'Banking Priority': 'N'
            },
            'Text': {
                '20': settlementFile.traditional.swiftReference,
                '23B': 'CRED',
                '32A': `${new Date().toISOString().split('T')[0].replace(/-/g, '')}EUR${settlementFile.blockchain.value}`,
                '50K': settlementFile.blockchain.from,
                '59': settlementFile.blockchain.to,
                '71A': 'OUR',
                '72': `/TOKEN/${settlementFile.blockchain.hash}`
            }
        };

        return JSON.stringify(swift, null, 2);
    }
}
