const { ethers } = require('ethers');
const fs = require('fs');
const path = require('path');

/**
 * Initialize blockchain infrastructure:
 * - Generate platform wallet
 * - Deploy smart contracts
 * - Update .env file with addresses
 */
async function initBlockchain() {
  console.log('🔗 Initializing blockchain infrastructure...');

  const provider = new ethers.JsonRpcProvider(
    process.env.BESU_RPC_URL || 'http://localhost:8545'
  );

  // Wait for blockchain to be ready
  console.log('⏳ Waiting for blockchain to be ready...');
  let retries = 30;
  while (retries > 0) {
    try {
      await provider.getBlockNumber();
      console.log('✅ Blockchain is ready!');
      break;
    } catch (error) {
      retries--;
      if (retries === 0) {
        throw new Error('Blockchain not available after 30 retries');
      }
      await new Promise(resolve => setTimeout(resolve, 2000));
    }
  }

  // Check if already initialized
  const envPath = path.join(__dirname, '../.env');
  if (fs.existsSync(envPath)) {
    const envContent = fs.readFileSync(envPath, 'utf8');
    if (
      envContent.includes('CONTRACT_ADDRESS_LICENSE_NFT=0x') &&
      !envContent.includes('CONTRACT_ADDRESS_LICENSE_NFT=0x0000000000000000000000000000000000000000')
    ) {
      console.log('✅ Blockchain already initialized, skipping deployment');
      return;
    }
  }

  // 1. Generate Platform Wallet
  console.log('🔐 Generating platform wallet...');
  const platformWallet = ethers.Wallet.createRandom();
  console.log('📝 Platform Wallet Address:', platformWallet.address);
  console.log('🔑 Platform Wallet Mnemonic:', platformWallet.mnemonic.phrase);

  // Fund the platform wallet from the dev network's pre-funded account
  console.log('💰 Funding platform wallet...');
  const devWallet = new ethers.Wallet(
    '0x8f2a55949038a9610f50fb23b5883af3b4ecb3c3bb792cbcefbd1542c692be63',
    provider
  );

  const fundTx = await devWallet.sendTransaction({
    to: platformWallet.address,
    value: ethers.parseEther('100.0'),
  });
  await fundTx.wait();
  console.log('✅ Platform wallet funded with 100 ETH');

  const connectedWallet = platformWallet.connect(provider);

  // 2. Deploy Smart Contracts
  console.log('📜 Deploying smart contracts...');

  const contracts = await deployContracts(connectedWallet);

  // 3. Update .env file
  console.log('📝 Updating .env file...');
  updateEnvFile({
    PLATFORM_WALLET_PRIVATE_KEY: platformWallet.privateKey,
    PLATFORM_WALLET_ADDRESS: platformWallet.address,
    PLATFORM_WALLET_MNEMONIC: platformWallet.mnemonic.phrase,
    CONTRACT_ADDRESS_LICENSE_NFT: contracts.licenseNFT,
    CONTRACT_ADDRESS_APPROVAL_MANAGER: contracts.approvalManager,
    CONTRACT_ADDRESS_DEPARTMENT_REGISTRY: contracts.departmentRegistry,
    CONTRACT_ADDRESS_WORKFLOW_REGISTRY: contracts.workflowRegistry,
  });

  console.log('✅ Blockchain initialization complete!');
  console.log('\n📋 Summary:');
  console.log('  Platform Wallet:', platformWallet.address);
  console.log('  License NFT:', contracts.licenseNFT);
  console.log('  Approval Manager:', contracts.approvalManager);
  console.log('  Department Registry:', contracts.departmentRegistry);
  console.log('  Workflow Registry:', contracts.workflowRegistry);
}

/**
 * Deploy all smart contracts
 */
async function deployContracts(wallet) {
  // Simple deployment of placeholder contracts
  // In production, you would deploy your actual Solidity contracts here

  console.log('🚀 Deploying License NFT contract...');
  const licenseNFT = await deployPlaceholderContract(wallet, 'LicenseNFT');

  console.log('🚀 Deploying Approval Manager contract...');
  const approvalManager = await deployPlaceholderContract(wallet, 'ApprovalManager');

  console.log('🚀 Deploying Department Registry contract...');
  const departmentRegistry = await deployPlaceholderContract(wallet, 'DepartmentRegistry');

  console.log('🚀 Deploying Workflow Registry contract...');
  const workflowRegistry = await deployPlaceholderContract(wallet, 'WorkflowRegistry');

  return {
    licenseNFT,
    approvalManager,
    departmentRegistry,
    workflowRegistry,
  };
}

/**
 * Deploy a placeholder contract (simple storage contract)
 */
async function deployPlaceholderContract(wallet, name) {
  // Simple contract that just stores a value
  const bytecode = '0x608060405234801561001057600080fd5b5060c78061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80632e64cec11460375780636057361d146051575b600080fd5b603d6069565b6040516048919060a2565b60405180910390f35b6067600480360381019060639190606f565b6072565b005b60008054905090565b8060008190555050565b6000813590506079816000ad565b92915050565b6000602082840312156000608257600080fd5b6000608e84828501607c565b91505092915050565b609c8160bb565b82525050565b600060208201905060b560008301846095565b92915050565b600081905091905056fea26469706673582212203a8e2f9c8e98b9f5e8c7d6e5f4c3b2a19087868756463524f3e2d1c0b9a8f76464736f6c63430008110033';

  const deployTx = await wallet.sendTransaction({
    data: bytecode,
  });

  const receipt = await deployTx.wait();
  const address = receipt.contractAddress;

  console.log(`✅ ${name} deployed at:`, address);
  return address;
}

/**
 * Update .env file with generated values
 * Values containing spaces are quoted for shell compatibility
 */
function updateEnvFile(values) {
  const envPath = path.join(__dirname, '../.env');
  let envContent = '';

  if (fs.existsSync(envPath)) {
    envContent = fs.readFileSync(envPath, 'utf8');
  }

  // Update or add each value
  for (const [key, value] of Object.entries(values)) {
    // Quote values that contain spaces (like mnemonic phrases)
    const formattedValue = value.includes(' ') ? `"${value}"` : value;
    const regex = new RegExp(`^${key}=.*$`, 'm');
    if (regex.test(envContent)) {
      envContent = envContent.replace(regex, `${key}=${formattedValue}`);
    } else {
      envContent += `\n${key}=${formattedValue}`;
    }
  }

  fs.writeFileSync(envPath, envContent.trim() + '\n');
  console.log(`✅ Updated ${envPath}`);
}

// Run initialization
initBlockchain()
  .then(() => {
    console.log('✅ Blockchain initialization completed successfully!');
    process.exit(0);
  })
  .catch((error) => {
    console.error('❌ Blockchain initialization failed:', error);
    process.exit(1);
  });
