/**
 * Copyright (c) 2024-2026 Тарабанов Александр Викторович
 * All rights reserved.
 * 
 * This software is proprietary and confidential.
 * Unauthorized copying, modification, or distribution is prohibited.
 * 
 * For licensing inquiries: info@hb3-accelerator.com
 * Website: https://hb3-accelerator.com
 * GitHub: https://github.com/VC-HB3-Accelerator
 */

const express = require('express');
const router = express.Router();
const { ethers } = require('ethers');
const rpcProviderService = require('../services/rpcProviderService');
const DeployParamsService = require('../services/deployParamsService');

/**
 * Получить информацию о мультиконтрактном предложении
 * @route POST /api/dle-multichain/get-proposal-multichain-info
 */
router.post('/get-proposal-multichain-info', async (req, res) => {
  try {
    const { dleAddress, proposalId, governanceChainId } = req.body;
    
    if (!dleAddress || proposalId === undefined || !governanceChainId) {
      return res.status(400).json({
        success: false,
        error: 'Адрес DLE, ID предложения и ID сети голосования обязательны'
      });
    }

    console.log(`[DLE Multichain] Получение информации о предложении ${proposalId} для DLE: ${dleAddress}`);

    // Получаем RPC URL для сети голосования
    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(governanceChainId);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: `RPC URL для сети ${governanceChainId} не найден`
      });
    }

    const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
    
    const dleAbi = [
      "function proposals(uint256) external view returns (uint256 id, string memory description, uint256 forVotes, uint256 againstVotes, bool executed, bool canceled, uint256 deadline, address initiator, bytes memory operation, uint256 governanceChainId, uint256 snapshotTimepoint, uint256[] memory targetChains)",
      "function getProposalState(uint256 _proposalId) external view returns (uint8 state)",
      "function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
      "function getSupportedChainCount() external view returns (uint256)",
      "function getSupportedChainId(uint256 _index) external view returns (uint256)"
    ];

    const dle = new ethers.Contract(dleAddress, dleAbi, provider);

    // Получаем данные предложения
    const proposal = await dle.proposals(proposalId);
    const state = await dle.getProposalState(proposalId);
    const result = await dle.checkProposalResult(proposalId);

    // Получаем поддерживаемые сети
    const chainCount = await dle.getSupportedChainCount();
    const supportedChains = [];
    for (let i = 0; i < chainCount; i++) {
      const chainId = await dle.getSupportedChainId(i);
      supportedChains.push(Number(chainId));
    }

    const proposalInfo = {
      id: Number(proposal.id),
      description: proposal.description,
      forVotes: Number(proposal.forVotes),
      againstVotes: Number(proposal.againstVotes),
      executed: proposal.executed,
      canceled: proposal.canceled,
      deadline: Number(proposal.deadline),
      initiator: proposal.initiator,
      operation: proposal.operation,
      governanceChainId: Number(proposal.governanceChainId),
      targetChains: proposal.targetChains.map(chain => Number(chain)),
      snapshotTimepoint: Number(proposal.snapshotTimepoint),
      state: Number(state),
      isPassed: result.passed,
      quorumReached: result.quorumReached,
      supportedChains: supportedChains,
      canExecuteInTargetChains: result.passed && result.quorumReached && !proposal.executed && !proposal.canceled
    };

    console.log(`[DLE Multichain] Информация о предложении получена:`, proposalInfo);

    res.json({
      success: true,
      data: proposalInfo
    });

  } catch (error) {
    console.error('[DLE Multichain] Ошибка при получении информации о предложении:', error);
    res.status(500).json({
      success: false,
      error: 'Ошибка при получении информации о предложении: ' + error.message
    });
  }
});

/**
 * Исполнить предложение во всех целевых сетях
 * @route POST /api/dle-multichain/execute-in-all-target-chains
 */
router.post('/execute-in-all-target-chains', async (req, res) => {
  try {
    const { dleAddress, proposalId, deploymentId, userAddress } = req.body;
    
    if (!dleAddress || proposalId === undefined || !deploymentId || !userAddress) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Multichain] Исполнение предложения ${proposalId} во всех целевых сетях для DLE: ${dleAddress}`);

    // Получаем параметры деплоя
    const deployParamsService = new DeployParamsService();
    const deployParams = await deployParamsService.getDeployParams(deploymentId);
    
    if (!deployParams || !deployParams.privateKey) {
      return res.status(400).json({
        success: false,
        error: 'Приватный ключ не найден в параметрах деплоя'
      });
    }

    // Получаем информацию о предложении
    const proposalInfoResponse = await fetch(`${req.protocol}://${req.get('host')}/api/dle-multichain/get-proposal-multichain-info`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        dleAddress,
        proposalId,
        governanceChainId: deployParams.currentChainId
      })
    });

    const proposalInfo = await proposalInfoResponse.json();
    
    if (!proposalInfo.success) {
      return res.status(400).json({
        success: false,
        error: 'Не удалось получить информацию о предложении'
      });
    }

    const { targetChains, canExecuteInTargetChains } = proposalInfo.data;

    if (!canExecuteInTargetChains) {
      return res.status(400).json({
        success: false,
        error: 'Предложение не готово к исполнению в целевых сетях'
      });
    }

    if (targetChains.length === 0) {
      return res.status(400).json({
        success: false,
        error: 'У предложения нет целевых сетей для исполнения'
      });
    }

    // Исполняем в каждой целевой сети
    const executionResults = [];
    
    for (const targetChainId of targetChains) {
      try {
        console.log(`[DLE Multichain] Исполнение в сети ${targetChainId}`);
        
        const result = await executeProposalInChain(
          dleAddress,
          proposalId,
          targetChainId,
          deployParams.privateKey,
          userAddress
        );
        
        executionResults.push({
          chainId: targetChainId,
          success: true,
          transactionHash: result.transactionHash
        });
        
      } catch (error) {
        console.error(`[DLE Multichain] Ошибка исполнения в сети ${targetChainId}:`, error.message);
        executionResults.push({
          chainId: targetChainId,
          success: false,
          error: error.message
        });
      }
    }

    const successCount = executionResults.filter(r => r.success).length;
    const totalCount = executionResults.length;

    console.log(`[DLE Multichain] Исполнение завершено: ${successCount}/${totalCount} успешно`);

    res.json({
      success: true,
      data: {
        proposalId,
        targetChains,
        executionResults,
        summary: {
          total: totalCount,
          successful: successCount,
          failed: totalCount - successCount
        }
      }
    });

  } catch (error) {
    console.error('[DLE Multichain] Ошибка при исполнении во всех целевых сетях:', error);
    res.status(500).json({
      success: false,
      error: 'Ошибка при исполнении во всех целевых сетях: ' + error.message
    });
  }
});

/**
 * Исполнить предложение в конкретной целевой сети
 * @route POST /api/dle-multichain/execute-in-target-chain
 */
router.post('/execute-in-target-chain', async (req, res) => {
  try {
    const { dleAddress, proposalId, targetChainId, deploymentId, userAddress } = req.body;
    
    if (!dleAddress || proposalId === undefined || !targetChainId || !deploymentId || !userAddress) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Multichain] Исполнение предложения ${proposalId} в сети ${targetChainId} для DLE: ${dleAddress}`);

    // Получаем параметры деплоя
    const deployParamsService = new DeployParamsService();
    const deployParams = await deployParamsService.getDeployParams(deploymentId);
    
    if (!deployParams || !deployParams.privateKey) {
      return res.status(400).json({
        success: false,
        error: 'Приватный ключ не найден в параметрах деплоя'
      });
    }

    // Исполняем в целевой сети
    const result = await executeProposalInChain(
      dleAddress,
      proposalId,
      targetChainId,
      deployParams.privateKey,
      userAddress
    );

    res.json({
      success: true,
      data: {
        proposalId,
        targetChainId,
        transactionHash: result.transactionHash,
        blockNumber: result.blockNumber
      }
    });

  } catch (error) {
    console.error('[DLE Multichain] Ошибка при исполнении в целевой сети:', error);
    res.status(500).json({
      success: false,
      error: 'Ошибка при исполнении в целевой сети: ' + error.message
    });
  }
});

/**
 * Вспомогательная функция для исполнения предложения в конкретной сети
 */
async function executeProposalInChain(dleAddress, proposalId, chainId, privateKey, userAddress) {
  // Получаем RPC URL для целевой сети
  const rpcUrl = await rpcProviderService.getRpcUrlByChainId(chainId);
  if (!rpcUrl) {
    throw new Error(`RPC URL для сети ${chainId} не найден`);
  }

  const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
  const wallet = new ethers.Wallet(privateKey, provider);
  
  const dleAbi = [
    "function executeProposalBySignatures(uint256 _proposalId, address[] calldata signers, bytes[] calldata signatures) external"
  ];

  const dle = new ethers.Contract(dleAddress, dleAbi, wallet);

  // Для простоты используем подпись от одного адреса (кошелька с приватным ключом)
  // В реальности нужно собрать подписи от держателей токенов
  const signers = [wallet.address];
  const signatures = []; // TODO: Реализовать сбор подписей

  // Временная заглушка - используем прямое исполнение если это возможно
  // В реальности нужно реализовать сбор подписей от держателей токенов
  try {
    // Пытаемся исполнить напрямую (если это сеть голосования)
    const directExecuteAbi = [
      "function executeProposal(uint256 _proposalId) external"
    ];
    
    const directDle = new ethers.Contract(dleAddress, directExecuteAbi, wallet);
    const tx = await directDle.executeProposal(proposalId);
    const receipt = await tx.wait();

    return {
      transactionHash: receipt.hash,
      blockNumber: receipt.blockNumber
    };
    
  } catch (directError) {
    // Если прямое исполнение невозможно, используем подписи
    if (signatures.length === 0) {
      throw new Error('Необходимо собрать подписи от держателей токенов для исполнения в целевой сети');
    }

    const tx = await dle.executeProposalBySignatures(proposalId, signers, signatures);
    const receipt = await tx.wait();

    return {
      transactionHash: receipt.hash,
      blockNumber: receipt.blockNumber
    };
  }
}

module.exports = router;


