// In renderer process (web page).
const {
  ipcRenderer
} = require("electron");

class PaperclipBlockchain {
  constructor() {
    this.isConnected = false;
    this.gasPrice = 1; // 1 CLIP per gas unit
    this.gasLimits = {
      'transfer': 21000,
      'contract_call': 50000,
      'contract_deploy': 100000,
      'multisig_create': 75000,
      'multisig': 35000
    };
  }

  async getStatus() {
    try {
      const result = await ipcRenderer.invoke("paperclip-get-status");
      this.isConnected = true;
      return result;
    } catch (error) {
      this.isConnected = false;
      throw error;
    }
  }

  async getBlock(blockHeight, clbError, clbSuccess) {
    try {
      const block = await ipcRenderer.invoke("paperclip-get-block", blockHeight);
      clbSuccess(block);
    } catch (error) {
      clbError(error);
    }
  }

  async getBalance(address, clbError, clbSuccess) {
    try {
      const balance = await ipcRenderer.invoke("paperclip-get-balance", address);
      clbSuccess(balance);
    } catch (error) {
      clbError(error);
    }
  }

  async getNonce(address, clbError, clbSuccess) {
    try {
      const nonce = await ipcRenderer.invoke("paperclip-get-nonce", address);
      clbSuccess(nonce);
    } catch (error) {
      clbError(error);
    }
  }

  isAddress(address) {
    // CLIPS address validation: CLIP- followed by 64 hex characters
    if (!address || typeof address !== 'string') {
      return false;
    }
    return /^CLIP-[0-9A-Fa-f]{64}$/.test(address);
  }

  async getTransaction(txHash, clbError, clbSuccess) {
    try {
      const transaction = await ipcRenderer.invoke("paperclip-get-transaction", txHash);
      clbSuccess(transaction);
    } catch (error) {
      clbError(error);
    }
  }

  async getTransactionFee(fromAddress, toAddress, amount, txType = 'transfer', clbError, clbSuccess) {
    try {
      // Calculate gas needed based on transaction type
      const gasNeeded = this.gasLimits[txType] || this.gasLimits['transfer'];
      const fee = gasNeeded * this.gasPrice;
      
      clbSuccess({
        gasNeeded: gasNeeded,
        gasPrice: this.gasPrice,
        totalFee: fee
      });
    } catch (error) {
      clbError(error);
    }
  }

  async prepareTransaction(privateKey, fromAddress, toAddress, amount, txType = 'transfer', data = '', clbError, clbSuccess) {
    try {
      // Get current nonce
      const nonce = await ipcRenderer.invoke("paperclip-get-nonce", fromAddress);
      
      // Calculate gas
      const gasNeeded = this.gasLimits[txType] || this.gasLimits['transfer'];
      
      // Create transaction object
      const ClipsCrypto = require('../modules/clips-crypto.js');
      const transaction = ClipsCrypto.createTransaction({
        sender: fromAddress,
        receiver: toAddress,
        amount: parseInt(amount),
        nonce: nonce,
        type: txType,
        data: data,
        privateKey: privateKey
      });
      
      // Add gas information
      transaction.gas = gasNeeded;
      transaction.gasPrice = this.gasPrice;
      transaction.fee = gasNeeded * this.gasPrice;
      
      clbSuccess(transaction);
    } catch (error) {
      clbError(error);
    }
  }

  async sendTransaction(transaction, clbError, clbSuccess) {
    try {
      // Convert transaction to hex for broadcasting
      const ClipsCrypto = require('../modules/clips-crypto.js');
      const txHex = ClipsCrypto.transactionToHex(transaction);
      
      // Broadcast transaction
      const result = await ipcRenderer.invoke("paperclip-broadcast-tx", txHex);
      
      if (result.success) {
        clbSuccess({
          hash: result.hash,
          height: result.height
        });
      } else {
        clbError(result.error || "Transaction failed");
      }
    } catch (error) {
      clbError(error);
    }
  }

  async getAccountsData(clbError, clbSuccess) {
    try {
      const rendererData = {
        sumBalance: 0,
        addressData: []
      };

      // Get stored wallets from database
      const wallets = PaperclipDatabase.getWallets();
      
      if (!wallets || !wallets.addresses || wallets.addresses.length === 0) {
        clbSuccess(rendererData);
        return;
      }

      // Get balance for each address
      let processedCount = 0;
      const totalAddresses = wallets.addresses.length;

      for (let i = 0; i < wallets.addresses.length; i++) {
        const address = wallets.addresses[i];
        const walletName = wallets.names[address] || `Account ${i + 1}`;

        try {
          const balance = await ipcRenderer.invoke("paperclip-get-balance", address);
          
          rendererData.addressData.push({
            address: address,
            name: walletName,
            balance: balance,
            balanceFormatted: this.formatBalance(balance)
          });
          
          rendererData.sumBalance += balance;
          
        } catch (error) {
          console.error(`Failed to get balance for ${address}:`, error);
          
          rendererData.addressData.push({
            address: address,
            name: walletName,
            balance: 0,
            balanceFormatted: "0 CLIPS",
            error: true
          });
        }

        processedCount++;
        
        // If all addresses processed, return data
        if (processedCount === totalAddresses) {
          rendererData.sumBalanceFormatted = this.formatBalance(rendererData.sumBalance);
          clbSuccess(rendererData);
        }
      }
      
    } catch (error) {
      clbError(error);
    }
  }

  formatBalance(balance) {
    if (balance === 0) {
      return "0 CLIPS";
    }
    
    // Format balance with appropriate decimal places
    if (balance >= 1000000) {
      return (balance / 1000000).toFixed(2) + "M CLIPS";
    } else if (balance >= 1000) {
      return (balance / 1000).toFixed(2) + "K CLIPS";
    } else {
      return balance.toLocaleString() + " CLIPS";
    }
  }

  async getNetworkInfo(clbError, clbSuccess) {
    try {
      const status = await this.getStatus();
      
      const networkInfo = {
        nodeInfo: status.result.node_info,
        syncInfo: status.result.sync_info,
        validatorInfo: status.result.validator_info,
        chainId: status.result.node_info.network,
        latestBlockHeight: status.result.sync_info.latest_block_height,
        catching_up: status.result.sync_info.catching_up
      };
      
      clbSuccess(networkInfo);
    } catch (error) {
      clbError(error);
    }
  }

  async getContractInfo(contractAddress, clbError, clbSuccess) {
    try {
      const contractInfo = await ipcRenderer.invoke("paperclip-get-contract", contractAddress);
      clbSuccess(contractInfo);
    } catch (error) {
      clbError(error);
    }
  }

  async getMultisigInfo(multisigAddress, clbError, clbSuccess) {
    try {
      const multisigInfo = await ipcRenderer.invoke("paperclip-get-multisig", multisigAddress);
      clbSuccess(multisigInfo);
    } catch (error) {
      clbError(error);
    }
  }

  async getFeePool(clbError, clbSuccess) {
    try {
      const feePool = await ipcRenderer.invoke("paperclip-get-fee-pool");
      clbSuccess({
        totalFees: feePool,
        formatted: this.formatBalance(feePool)
      });
    } catch (error) {
      clbError(error);
    }
  }

  // Utility method to validate transaction before sending
  validateTransaction(transaction) {
    const errors = [];
    
    if (!this.isAddress(transaction.sender)) {
      errors.push("Invalid sender address");
    }
    
    if (!this.isAddress(transaction.receiver)) {
      errors.push("Invalid receiver address");
    }
    
    if (!transaction.amount || transaction.amount <= 0) {
      errors.push("Invalid amount");
    }
    
    if (transaction.nonce < 0) {
      errors.push("Invalid nonce");
    }
    
    if (!transaction.signature) {
      errors.push("Transaction not signed");
    }
    
    return {
      isValid: errors.length === 0,
      errors: errors
    };
  }
}

// Create global instance
const PaperclipChain = new PaperclipBlockchain();

// Make it available globally (maintaining compatibility with existing code)
window.PaperclipChain = PaperclipChain;