/**
 * @file xrpl-connector.ts
 * @notice Cacti XRPL connector for bridging to XRPL
 */

import { xrpl } from 'xrpl';

export interface XRPLConfig {
    server: string; // XRPL server URL
    account: string; // Bridge account address
    secret: string; // Bridge account secret
    destinationTag?: number; // Optional destination tag
}

export interface XRPLTransferRequest {
    destination: string; // XRPL destination address
    amount: string; // Amount in drops (1 XRP = 1,000,000 drops)
    destinationTag?: number;
    memo?: string;
}

export interface XRPLTransferResult {
    txHash: string;
    ledgerIndex: number;
    validated: boolean;
    fee: string;
}

export class XRPLConnector {
    private client: xrpl.Client;
    private config: XRPLConfig;
    private wallet: xrpl.Wallet;

    constructor(config: XRPLConfig) {
        this.config = config;
        this.client = new xrpl.Client(config.server);
        this.wallet = xrpl.Wallet.fromSecret(config.secret);
    }

    /**
     * Connect to XRPL
     */
    async connect(): Promise<void> {
        await this.client.connect();
    }

    /**
     * Disconnect from XRPL
     */
    async disconnect(): Promise<void> {
        await this.client.disconnect();
    }

    /**
     * Send XRP payment
     */
    async sendPayment(request: XRPLTransferRequest): Promise<XRPLTransferResult> {
        if (!this.client.isConnected()) {
            await this.connect();
        }

        // Prepare payment transaction
        const payment: xrpl.Payment = {
            TransactionType: 'Payment',
            Account: this.wallet.classicAddress,
            Destination: request.destination,
            Amount: request.amount, // Amount in drops
            DestinationTag: request.destinationTag || this.config.destinationTag,
            Memos: request.memo ? [
                {
                    Memo: {
                        MemoData: Buffer.from(request.memo).toString('hex')
                    }
                }
            ] : undefined
        };

        // Submit transaction
        const prepared = await this.client.autofill(payment);
        const signed = this.wallet.sign(prepared);
        const result = await this.client.submitAndWait(signed.tx_blob);

        if (result.result.meta?.TransactionResult !== 'tesSUCCESS') {
            throw new Error(`XRPL transaction failed: ${result.result.meta?.TransactionResult}`);
        }

        return {
            txHash: result.result.hash || '',
            ledgerIndex: result.result.ledger_index || 0,
            validated: result.result.validated || false,
            fee: result.result.Fee || '0'
        };
    }

    /**
     * Get account balance
     */
    async getBalance(): Promise<string> {
        if (!this.client.isConnected()) {
            await this.connect();
        }

        const accountInfo = await this.client.request({
            command: 'account_info',
            account: this.wallet.classicAddress
        });

        return accountInfo.result.account_data.Balance || '0';
    }

    /**
     * Get transaction status
     */
    async getTransactionStatus(txHash: string): Promise<{
        validated: boolean;
        ledgerIndex?: number;
        result?: string;
    }> {
        if (!this.client.isConnected()) {
            await this.connect();
        }

        const tx = await this.client.request({
            command: 'tx',
            transaction: txHash
        });

        return {
            validated: tx.result.validated || false,
            ledgerIndex: tx.result.ledger_index,
            result: tx.result.meta?.TransactionResult
        };
    }

    /**
     * Wait for finality (ledger close)
     */
    async waitForFinality(ledgerIndex: number, timeout: number = 60000): Promise<boolean> {
        const startTime = Date.now();

        while (Date.now() - startTime < timeout) {
            const ledger = await this.client.request({
                command: 'ledger',
                ledger_index: ledgerIndex
            });

            if (ledger.result.ledger?.closed) {
                return true;
            }

            await new Promise(resolve => setTimeout(resolve, 1000));
        }

        return false;
    }

    /**
     * Convert XRP to drops
     */
    static xrpToDrops(xrp: string): string {
        return xrpl.xrpToDrops(xrp);
    }

    /**
     * Convert drops to XRP
     */
    static dropsToXrp(drops: string): string {
        return xrpl.dropsToXrp(drops);
    }
}
