/**
 * 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 { getSupportedChainIds } = require('../utils/networkLoader');

// Получение списка всех предложений
router.post('/get-proposals', async (req, res) => {
  try {
    const { dleAddress } = req.body;
    
    if (!dleAddress) {
      return res.status(400).json({
        success: false,
        error: 'Адрес DLE обязателен'
      });
    }

    console.log(`[DLE Proposals] Получение списка предложений для DLE: ${dleAddress}`);

    // Получаем поддерживаемые сети DLE из контракта
    let supportedChains = [];
    try {
      // Определяем корректную сеть для данного адреса
      let rpcUrl, targetChainId;
      // Получаем поддерживаемые сети из deploy_params
      const candidateChainIds = await getSupportedChainIds();
      
      for (const cid of candidateChainIds) {
        try {
          const url = await rpcProviderService.getRpcUrlByChainId(cid);
          if (!url) continue;
          const prov = new ethers.JsonRpcProvider(url);
          const code = await prov.getCode(dleAddress);
          if (code && code !== '0x') { 
            rpcUrl = url; 
            targetChainId = cid; 
            break; 
          }
        } catch (_) {}
      }
      
      if (!rpcUrl) {
        console.log(`[DLE Proposals] Не удалось найти сеть для адреса ${dleAddress}`);
        // Fallback к известным сетям из deploy_params или базовые
        supportedChains = candidateChainIds.length > 0 ? candidateChainIds : [11155111, 17000, 421614, 84532];
        console.log(`[DLE Proposals] Используем fallback сети:`, supportedChains);
        // НЕ делаем return - продолжаем искать предложения в fallback сетях
      }
      if (rpcUrl) {
        const provider = new ethers.JsonRpcProvider(rpcUrl);
        const dleAbi = [
          "function getSupportedChainCount() external view returns (uint256)",
          "function getSupportedChainId(uint256 _index) external view returns (uint256)"
        ];
        const dle = new ethers.Contract(dleAddress, dleAbi, provider);
        
        const chainCount = await dle.getSupportedChainCount();
        console.log(`[DLE Proposals] Количество поддерживаемых сетей: ${chainCount}`);
        
        for (let i = 0; i < Number(chainCount); i++) {
          const chainId = await dle.getSupportedChainId(i);
          supportedChains.push(Number(chainId));
        }
        
        console.log(`[DLE Proposals] Поддерживаемые сети из контракта:`, supportedChains);
      }
    } catch (error) {
      console.log(`[DLE Proposals] Ошибка получения поддерживаемых сетей из контракта:`, error.message);
      // Fallback к известным сетям
      supportedChains = [11155111, 17000, 421614, 84532];
      console.log(`[DLE Proposals] Используем fallback сети:`, supportedChains);
    }
    
    const allProposals = [];
    
    // Ищем предложения во всех поддерживаемых сетях
    for (const chainId of supportedChains) {
      try {
        console.log(`[DLE Proposals] Поиск предложений в сети ${chainId}...`);
        
        const rpcUrl = await rpcProviderService.getRpcUrlByChainId(chainId);
        if (!rpcUrl) {
          console.log(`[DLE Proposals] RPC URL для сети ${chainId} не найден, пропускаем`);
          continue;
        }

        const provider = new ethers.JsonRpcProvider(rpcUrl);
        
        // Проверяем, что контракт существует по этому адресу в текущей сети
        const contractCode = await provider.getCode(dleAddress);
        if (!contractCode || contractCode === '0x') {
          console.log(`[DLE Proposals] Контракт по адресу ${dleAddress} не найден в сети ${chainId}, пропускаем`);
          continue;
        }
        
        // ABI для чтения предложений (используем getProposalSummary для мультиконтрактов)
        const dleAbi = [
          "function getProposalState(uint256 _proposalId) external view returns (uint8 state)",
          "function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
          "function getProposalSummary(uint256 _proposalId) external view returns (uint256 id, string memory description, uint256 forVotes, uint256 againstVotes, bool executed, bool canceled, uint256 deadline, address initiator, uint256 governanceChainId, uint256 snapshotTimepoint, uint256[] memory targetChains)",
          "function quorumPercentage() external view returns (uint256)",
          "function getPastTotalSupply(uint256 timepoint) external view returns (uint256)",
          "function totalSupply() external view returns (uint256)",
          "event ProposalCreated(uint256 proposalId, address initiator, string description)"
        ];

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

        // Получаем события ProposalCreated для определения количества предложений
        const currentBlock = await provider.getBlockNumber();
        // RPC провайдеры ограничивают запрос до 10000 блоков, поэтому разбиваем на части
        const maxBlockRange = 10000;
        const searchRange = 50000; // Ищем в последних 50000 блоках
        const fromBlock = Math.max(0, currentBlock - searchRange);
        
        console.log(`[DLE Proposals] Проверка контракта ${dleAddress} в сети ${chainId}, диапазон блоков: ${fromBlock} - ${currentBlock}`);
        
        // Разбиваем запрос на части по 10000 блоков
        let allEvents = [];
        let searchFromBlock = fromBlock;
        
        while (searchFromBlock < currentBlock) {
          const searchToBlock = Math.min(searchFromBlock + maxBlockRange - 1, currentBlock);
          console.log(`[DLE Proposals] Запрос событий для блоков ${searchFromBlock} - ${searchToBlock}`);
          
          try {
            const chunkEvents = await dle.queryFilter('ProposalCreated', searchFromBlock, searchToBlock);
            allEvents = allEvents.concat(chunkEvents);
            console.log(`[DLE Proposals] Найдено событий в диапазоне ${searchFromBlock}-${searchToBlock}: ${chunkEvents.length}`);
          } catch (chunkError) {
            console.error(`[DLE Proposals] Ошибка при запросе блоков ${searchFromBlock}-${searchToBlock}:`, chunkError.message);
            // Продолжаем с следующим диапазоном
          }
          
          searchFromBlock = searchToBlock + 1;
          
          // Небольшая задержка между запросами для избежания rate limiting
          if (searchFromBlock < currentBlock) {
            await new Promise(resolve => setTimeout(resolve, 100));
          }
        }
        
        const events = allEvents;
        
        console.log(`[DLE Proposals] Найдено событий ProposalCreated в сети ${chainId}: ${events.length}`);
        console.log(`[DLE Proposals] Диапазон блоков: ${fromBlock} - ${currentBlock}`);
        
        if (events.length === 0) {
          console.log(`[DLE Proposals] Предложения не найдены в сети ${chainId} для контракта ${dleAddress}`);
        }
        
        // Читаем информацию о каждом предложении
        for (let i = 0; i < events.length; i++) {
          try {
            const proposalId = events[i].args.proposalId;
            console.log(`[DLE Proposals] Читаем предложение ID: ${proposalId}`);
            
              // Пробуем несколько раз для новых предложений
              let proposalState, isPassed, quorumReached, forVotes, againstVotes, quorumRequired, currentTotalSupply, quorumPct;
              let retryCount = 0;
              const maxRetries = 1;
            
            while (retryCount < maxRetries) {
              try {
                proposalState = await dle.getProposalState(proposalId);
                const result = await dle.checkProposalResult(proposalId);
                isPassed = result.passed;
                quorumReached = result.quorumReached;
                
                // Получаем данные о голосах из структуры Proposal (включая мультиконтрактные поля)
                try {
                  const proposalData = await dle.getProposalSummary(proposalId);
                  forVotes = Number(proposalData.forVotes);
                  againstVotes = Number(proposalData.againstVotes);
                  
                  // Вычисляем требуемый кворум
                  quorumPct = Number(await dle.quorumPercentage());
                  const pastSupply = Number(await dle.getPastTotalSupply(proposalData.snapshotTimepoint));
                  quorumRequired = Math.floor((pastSupply * quorumPct) / 100);
                  
                    // Получаем текущий totalSupply для отображения
                    currentTotalSupply = Number(await dle.totalSupply());
                  
                  console.log(`[DLE Proposals] Кворум для предложения ${proposalId}:`, {
                    quorumPercentage: quorumPct,
                    pastSupply: pastSupply,
                    quorumRequired: quorumRequired,
                    quorumPercentageFormatted: `${quorumPct}%`,
                    snapshotTimepoint: proposalData.snapshotTimepoint,
                    pastSupplyFormatted: `${(pastSupply / 10**18).toFixed(2)} DLE`,
                    quorumRequiredFormatted: `${(quorumRequired / 10**18).toFixed(2)} DLE`
                  });
                } catch (voteError) {
                  console.log(`[DLE Proposals] Ошибка получения голосов для предложения ${proposalId}:`, voteError.message);
                  forVotes = 0;
                    againstVotes = 0;
                    quorumRequired = 0;
                    currentTotalSupply = 0;
                    quorumPct = 0;
                }
                
                break; // Успешно прочитали
              } catch (error) {
                retryCount++;
                console.log(`[DLE Proposals] Попытка ${retryCount} чтения предложения ${proposalId} не удалась:`, error.message);
                if (retryCount < maxRetries) {
                  await new Promise(resolve => setTimeout(resolve, 2000)); // Ждем 2 секунды
                } else {
                  throw error; // Превышено количество попыток
                }
              }
            }
            
            console.log(`[DLE Proposals] Данные предложения ${proposalId}:`, {
              id: Number(proposalId),
              description: events[i].args.description,
              state: Number(proposalState),
              isPassed: isPassed,
              quorumReached: quorumReached,
              forVotes: Number(forVotes),
              againstVotes: Number(againstVotes),
              quorumRequired: Number(quorumRequired),
              initiator: events[i].args.initiator
            });
            
            // Фильтруем предложения по времени - только за последние 30 дней
            const block = await provider.getBlock(events[i].blockNumber);
            const proposalTime = block.timestamp;
            const currentTime = Math.floor(Date.now() / 1000);
            const thirtyDaysAgo = currentTime - (30 * 24 * 60 * 60); // 30 дней назад
            
            if (proposalTime < thirtyDaysAgo) {
              console.log(`[DLE Proposals] Пропускаем старое предложение ${proposalId} (${new Date(proposalTime * 1000).toISOString()})`);
              continue;
            }
            
        // Показываем все предложения, включая выполненные и отмененные
        // Согласно контракту: 0=Pending, 1=Succeeded, 2=Defeated, 3=Executed, 4=Canceled, 5=ReadyForExecution
        // Убрали фильтрацию выполненных и отмененных предложений для отображения в UI
            
            // Создаем уникальный ID, включающий chainId
            const uniqueId = `${chainId}-${proposalId}`;
            
            // Получаем мультиконтрактные данные из proposalData (если доступны)
            let operation = null;
            let governanceChainId = null;
            let targetChains = [];
            let decodedOperation = null;
            let operationDescription = null;
            
            try {
              const proposalData = await dle.getProposalSummary(proposalId);
              governanceChainId = Number(proposalData.governanceChainId);
              targetChains = proposalData.targetChains.map(chain => Number(chain));
              
              // Получаем operation из отдельного вызова (если нужно)
              // operation не возвращается в getProposalSummary, но это не критично для мультиконтрактов
              operation = null; // Пока не реализовано
              
              // Декодируем операцию (если доступна)
              if (operation && operation !== '0x') {
                const { decodeOperation, formatOperation } = require('../utils/operationDecoder');
                decodedOperation = decodeOperation(operation);
                operationDescription = formatOperation(decodedOperation);
              }
            } catch (error) {
              console.log(`[DLE Proposals] Не удалось получить мультиконтрактные данные для предложения ${proposalId}:`, error.message);
            }

            const proposalInfo = {
              id: Number(proposalId),
              uniqueId: uniqueId,
              description: events[i].args.description,
              state: Number(proposalState),
              isPassed: isPassed,
              quorumReached: quorumReached,
              forVotes: Number(forVotes),
              againstVotes: Number(againstVotes),
              quorumRequired: Number(quorumRequired),
              totalSupply: Number(currentTotalSupply || 0), // Добавляем totalSupply
              contractQuorumPercentage: Number(quorumPct), // Добавляем процент кворума из контракта
              initiator: events[i].args.initiator,
              blockNumber: events[i].blockNumber,
              transactionHash: events[i].transactionHash,
              chainId: chainId, // Добавляем информацию о сети
              timestamp: proposalTime,
              createdAt: new Date(proposalTime * 1000).toISOString(),
              executed: Number(proposalState) === 3, // 3 = Executed
              canceled: Number(proposalState) === 4,  // 4 = Canceled
              // Мультиконтрактные поля
              operation: operation,
              governanceChainId: governanceChainId,
              targetChains: targetChains,
              isMultichain: targetChains && targetChains.length > 0,
              decodedOperation: decodedOperation,
              operationDescription: operationDescription
            };
            
            // Проверяем, нет ли уже такого предложения (по уникальному ID)
            const existingProposal = allProposals.find(p => p.uniqueId === uniqueId);
            if (!existingProposal) {
              allProposals.push(proposalInfo);
            } else {
              console.log(`[DLE Proposals] Пропускаем дубликат предложения ${uniqueId}`);
            }
          } catch (error) {
            console.log(`[DLE Proposals] Ошибка при чтении предложения ${i}:`, error.message);
            
            // Если это ошибка декодирования, возможно предложение еще не полностью записано
            if (error.message.includes('could not decode result data')) {
              console.log(`[DLE Proposals] Предложение ${i} еще не полностью синхронизировано, пропускаем`);
              continue;
            }
            
            // Продолжаем с следующим предложением
          }
        }
        
        console.log(`[DLE Proposals] Найдено предложений в сети ${chainId}: ${events.length}`);
        
      } catch (error) {
        console.log(`[DLE Proposals] Ошибка при поиске предложений в сети ${chainId}:`, error.message);
        // Продолжаем с следующей сетью
      }
    }

    // Сортируем по времени создания (новые сверху), затем по ID
    allProposals.sort((a, b) => {
      if (a.timestamp !== b.timestamp) {
        return b.timestamp - a.timestamp;
      }
      return b.id - a.id;
    });

    console.log(`[DLE Proposals] Найдено предложений: ${allProposals.length}`);

    res.json({
      success: true,
      data: {
        proposals: allProposals,
        totalCount: allProposals.length
      }
    });

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

// Получение информации о предложении
router.post('/get-proposal-info', async (req, res) => {
  try {
    const { dleAddress, proposalId } = req.body;
    
    if (!dleAddress || proposalId === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны: dleAddress, proposalId'
      });
    }

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

    // Определяем корректную сеть для данного адреса
    let rpcUrl, targetChainId;
    // Получаем поддерживаемые сети из deploy_params
    const candidateChainIds = await getSupportedChainIds();
    
    for (const cid of candidateChainIds) {
      try {
        const url = await rpcProviderService.getRpcUrlByChainId(cid);
        if (!url) continue;
        const prov = new ethers.JsonRpcProvider(url);
        const code = await prov.getCode(dleAddress);
        if (code && code !== '0x') { 
          rpcUrl = url; 
          targetChainId = cid; 
          break; 
        }
      } catch (_) {}
    }
    
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'Не удалось найти сеть, где по адресу есть контракт'
      });
    }
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);

    // ABI для чтения информации о предложении
    const dleAbi = [
      "function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
      "function getProposalState(uint256 _proposalId) external view returns (uint8 state)",
      "event ProposalCreated(uint256 proposalId, address initiator, string description)"
    ];

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

    // Ищем событие ProposalCreated для этого предложения
    const currentBlock = await provider.getBlockNumber();
    const fromBlock = Math.max(0, currentBlock - 10000);
    
    const events = await dle.queryFilter('ProposalCreated', fromBlock, currentBlock);
    const proposalEvent = events.find(event => Number(event.args.proposalId) === proposalId);
    
    if (!proposalEvent) {
      return res.status(404).json({
        success: false,
        error: 'Предложение не найдено'
      });
    }
    
    // Получаем состояние и результат предложения
    const result = await dle.checkProposalResult(proposalId);
    const state = await dle.getProposalState(proposalId);
    
    const proposalInfo = {
      id: Number(proposalId),
      description: proposalEvent.args.description,
      initiator: proposalEvent.args.initiator,
      blockNumber: proposalEvent.blockNumber,
      transactionHash: proposalEvent.transactionHash,
      state: Number(state),
      isPassed: result.passed,
      quorumReached: result.quorumReached
    };

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

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

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

// Получить состояние предложения
router.post('/get-proposal-state', async (req, res) => {
  try {
    const { dleAddress, proposalId } = req.body;

    if (!dleAddress || proposalId === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

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

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function getProposalState(uint256 _proposalId) public view returns (uint8 state)"
    ];

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

    // Получаем состояние предложения
    const state = await dle.getProposalState(proposalId);

    console.log(`[DLE Proposals] Состояние предложения ${proposalId}: ${state}`);

    res.json({
      success: true,
      data: {
        proposalId: Number(proposalId),
        state: Number(state)
      }
    });

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

// Получить голоса по предложению
router.post('/get-proposal-votes', async (req, res) => {
  try {
    const { dleAddress, proposalId } = req.body;

    if (!dleAddress || proposalId === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Proposals] Получение голосов по предложению ${proposalId} в DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
      "function getProposalState(uint256 _proposalId) external view returns (uint8 state)"
    ];

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

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

    console.log(`[DLE Proposals] Результат предложения ${proposalId}:`, { result, state });

    res.json({
      success: true,
      data: {
        proposalId: Number(proposalId),
        isPassed: result.passed,
        quorumReached: result.quorumReached,
        state: Number(state),
        // Пока не можем получить точные голоса, так как функция не существует в контракте
        forVotes: 0,
        againstVotes: 0,
        totalVotes: 0,
        quorumRequired: 0
      }
    });

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

// Получить количество предложений
router.post('/get-proposals-count', async (req, res) => {
  try {
    const { dleAddress } = req.body;
    
    if (!dleAddress) {
      return res.status(400).json({
        success: false,
        error: 'Адрес DLE обязателен'
      });
    }

    console.log(`[DLE Proposals] Получение количества предложений для DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function getProposalsCount() external view returns (uint256)"
    ];

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

    // Получаем количество предложений
    const count = await dle.getProposalsCount();

    console.log(`[DLE Proposals] Количество предложений: ${count}`);

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

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

// Получить список предложений с пагинацией
router.post('/list-proposals', async (req, res) => {
  try {
    const { dleAddress, offset, limit } = req.body;
    
    if (!dleAddress || offset === undefined || limit === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Proposals] Получение списка предложений для DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function listProposals(uint256 offset, uint256 limit) external view returns (uint256[] memory)"
    ];

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

    // Получаем список предложений
    const proposals = await dle.listProposals(offset, limit);

    console.log(`[DLE Proposals] Список предложений:`, proposals);

    res.json({
      success: true,
      data: {
        proposals: proposals.map(p => Number(p)),
        offset: Number(offset),
        limit: Number(limit)
      }
    });

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

// Получить голосующую силу на момент времени
router.post('/get-voting-power-at', async (req, res) => {
  try {
    const { dleAddress, voter, timepoint } = req.body;
    
    if (!dleAddress || !voter || timepoint === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Proposals] Получение голосующей силы для ${voter} в DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function getVotingPowerAt(address voter, uint256 timepoint) external view returns (uint256)"
    ];

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

    // Получаем голосующую силу
    const votingPower = await dle.getVotingPowerAt(voter, timepoint);

    console.log(`[DLE Proposals] Голосующая сила для ${voter}: ${votingPower}`);

    res.json({
      success: true,
      data: {
        voter: voter,
        timepoint: Number(timepoint),
        votingPower: Number(votingPower)
      }
    });

  } catch (error) {
    console.error('[DLE Proposals] Ошибка при получении голосующей силы:', error);
    res.status(500).json({
      success: false,
      error: 'Ошибка при получении голосующей силы: ' + error.message
    });
  }
});

// Получить требуемый кворум на момент времени
router.post('/get-quorum-at', async (req, res) => {
  try {
    const { dleAddress, timepoint } = req.body;
    
    if (!dleAddress || timepoint === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Proposals] Получение требуемого кворума для DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function getQuorumAt(uint256 timepoint) external view returns (uint256)"
    ];

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

    // Получаем требуемый кворум
    const quorum = await dle.getQuorumAt(timepoint);

    console.log(`[DLE Proposals] Требуемый кворум: ${quorum}`);

    res.json({
      success: true,
      data: {
        timepoint: Number(timepoint),
        quorum: Number(quorum)
      }
    });

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

// Исполнить предложение (подготовка транзакции для MetaMask)
router.post('/execute-proposal', async (req, res) => {
  try {
    console.log('[DLE Proposals] Получен запрос на исполнение предложения:', req.body);
    
    const { dleAddress, proposalId } = req.body;
    
    if (!dleAddress || proposalId === undefined) {
      console.log('[DLE Proposals] Ошибка валидации: отсутствуют обязательные поля');
      return res.status(400).json({
        success: false,
        error: 'Необходимы dleAddress и proposalId'
      });
    }

    console.log(`[DLE Proposals] Подготовка исполнения предложения ${proposalId} в DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function executeProposal(uint256 _proposalId) external"
    ];

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

    // Подготавливаем данные для транзакции (не отправляем)
    const txData = await dle.executeProposal.populateTransaction(proposalId);

    console.log(`[DLE Proposals] Данные транзакции исполнения подготовлены:`, txData);

    res.json({
      success: true,
      data: {
        to: dleAddress,
        data: txData.data,
        value: "0x0",
        gasLimit: "0x1e8480", // 2,000,000 gas
        message: `Подготовлены данные для исполнения предложения ${proposalId}. Отправьте транзакцию через MetaMask.`
      }
    });

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

// Отменить предложение
router.post('/cancel-proposal', async (req, res) => {
  try {
    const { dleAddress, proposalId, reason, userAddress } = req.body;
    
    if (!dleAddress || proposalId === undefined || !reason || !userAddress) {
      return res.status(400).json({
        success: false,
        error: 'Все поля обязательны'
      });
    }

    console.log(`[DLE Proposals] Отмена предложения ${proposalId} в DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function cancelProposal(uint256 _proposalId, string calldata reason) external"
    ];

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

    // Отменяем предложение
    const tx = await dle.cancelProposal(proposalId, reason);
    const receipt = await tx.wait();

    console.log(`[DLE Proposals] Предложение отменено:`, receipt);

    res.json({
      success: true,
      data: {
        transactionHash: receipt.hash
      }
    });

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

// Получить количество предложений
router.post('/get-proposals-count', async (req, res) => {
  try {
    const { dleAddress } = req.body;
    
    if (!dleAddress) {
      return res.status(400).json({
        success: false,
        error: 'Адрес DLE обязателен'
      });
    }

    console.log(`[DLE Proposals] Получение количества предложений для DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function getProposalsCount() external view returns (uint256)"
    ];

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

    const count = await dle.getProposalsCount();

    console.log(`[DLE Proposals] Количество предложений: ${count}`);

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

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

// Получить список предложений с пагинацией
router.post('/list-proposals', async (req, res) => {
  try {
    const { dleAddress, offset = 0, limit = 10 } = req.body;
    
    if (!dleAddress) {
      return res.status(400).json({
        success: false,
        error: 'Адрес DLE обязателен'
      });
    }

    console.log(`[DLE Proposals] Получение списка предложений для DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function listProposals(uint256 offset, uint256 limit) external view returns (uint256[] memory)",
      "function getProposalSummary(uint256 _proposalId) external view returns (uint256 id, string memory description, uint256 forVotes, uint256 againstVotes, bool executed, bool canceled, uint256 deadline, address initiator, uint256 governanceChainId, uint256 snapshotTimepoint, uint256[] memory targets)",
      "function getProposalState(uint256 _proposalId) external view returns (uint8 state)"
    ];

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

    // Получаем список ID предложений
    const proposalIds = await dle.listProposals(offset, limit);
    
    console.log(`[DLE Proposals] Получены ID предложений:`, proposalIds);
    console.log(`[DLE Proposals] Количество ID:`, proposalIds.length);
    
    const proposals = [];
    
    // Получаем детали каждого предложения
    console.log(`[DLE Proposals] Начинаем обработку предложений...`);
    for (const proposalId of proposalIds) {
      try {
        const proposal = await dle.getProposalSummary(proposalId);
        const state = await dle.getProposalState(proposalId);
        
        proposals.push({
          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,
          governanceChainId: Number(proposal.governanceChainId),
          snapshotTimepoint: Number(proposal.snapshotTimepoint),
          targetChains: proposal.targets.map(chain => Number(chain)),
          state: Number(state)
        });
      } catch (error) {
        console.log(`[DLE Proposals] Ошибка при получении деталей предложения ${proposalId}:`, error.message);
        // Добавляем базовую информацию о предложении
        proposals.push({
          id: Number(proposalId),
          description: `Предложение #${Number(proposalId)}`,
          forVotes: 0,
          againstVotes: 0,
          executed: false,
          canceled: false,
          deadline: 0,
          initiator: '0x0000000000000000000000000000000000000000',
          governanceChainId: 0,
          snapshotTimepoint: 0,
          targetChains: [],
          state: 0
        });
      }
    }

    console.log(`[DLE Proposals] Получено предложений: ${proposals.length}`);

    res.json({
      success: true,
      data: {
        proposals: proposals,
        offset: Number(offset),
        limit: Number(limit)
      }
    });

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

// Голосовать за предложение
router.post('/vote-proposal', async (req, res) => {
  try {
    const { dleAddress, proposalId, support } = req.body;
    
    if (!dleAddress || proposalId === undefined || support === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Необходимы dleAddress, proposalId и support'
      });
    }

    console.log(`[DLE Proposals] Голосование за предложение ${proposalId} в DLE: ${dleAddress}, поддержка: ${support}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    const dleAbi = [
      "function vote(uint256 _proposalId, bool _support) external"
    ];

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

    // Пропускаем проверку hasVoted - функция не существует в контракте
    console.log(`[DLE Proposals] Пропускаем проверку hasVoted - полагаемся на смарт-контракт`);

    // Подготавливаем данные для транзакции (не отправляем)
    const txData = await dle.vote.populateTransaction(proposalId, support);

    console.log(`[DLE Proposals] Данные транзакции голосования подготовлены:`, txData);

    res.json({
      success: true,
      data: {
        to: dleAddress,
        data: txData.data,
        value: "0x0",
        gasLimit: "0x1e8480", // 2,000,000 gas
        message: `Подготовлены данные для голосования ${support ? 'за' : 'против'} предложения ${proposalId}. Отправьте транзакцию через MetaMask.`
      }
    });

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

// Проверить статус голосования пользователя
router.post('/check-vote-status', async (req, res) => {
  try {
    const { dleAddress, proposalId, voterAddress } = req.body;
    
    if (!dleAddress || proposalId === undefined || !voterAddress) {
      return res.status(400).json({
        success: false,
        error: 'Необходимы dleAddress, proposalId и voterAddress'
      });
    }

    console.log(`[DLE Proposals] Проверка статуса голосования для ${voterAddress} по предложению ${proposalId} в DLE: ${dleAddress}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    // Функция hasVoted не существует в контракте DLE
    console.log(`[DLE Proposals] Функция hasVoted не поддерживается в контракте DLE`);
    
    const hasVoted = false; // Всегда возвращаем false, так как функция не существует

    res.json({
      success: true,
      data: {
        hasVoted: hasVoted,
        voterAddress: voterAddress,
        proposalId: proposalId
      }
    });

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

// Endpoint для отслеживания подтверждения транзакций голосования
router.post('/track-vote-transaction', async (req, res) => {
  try {
    const { txHash, dleAddress, proposalId, support } = req.body;
    
    if (!txHash || !dleAddress || proposalId === undefined || support === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Необходимы txHash, dleAddress, proposalId и support'
      });
    }

    console.log(`[DLE Proposals] Отслеживание транзакции голосования: ${txHash}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    // Ждем подтверждения транзакции
    const receipt = await provider.waitForTransaction(txHash, 1, 60000); // 60 секунд таймаут
    
    if (receipt && receipt.status === 1) {
      console.log(`[DLE Proposals] Транзакция голосования подтверждена: ${txHash}`);
      
      // Отправляем WebSocket уведомление
      const wsHub = require('../wsHub');
      wsHub.broadcastProposalVoted(dleAddress, proposalId, support, txHash);
      
      res.json({
        success: true,
        data: {
          txHash: txHash,
          status: 'confirmed',
          receipt: receipt
        }
      });
    } else {
      res.json({
        success: false,
        error: 'Транзакция не подтверждена или провалилась'
      });
    }

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

// Endpoint для отслеживания подтверждения транзакций исполнения
router.post('/track-execution-transaction', async (req, res) => {
  try {
    const { txHash, dleAddress, proposalId } = req.body;
    
    if (!txHash || !dleAddress || proposalId === undefined) {
      return res.status(400).json({
        success: false,
        error: 'Необходимы txHash, dleAddress и proposalId'
      });
    }

    console.log(`[DLE Proposals] Отслеживание транзакции исполнения: ${txHash}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    // Ждем подтверждения транзакции
    const receipt = await provider.waitForTransaction(txHash, 1, 60000); // 60 секунд таймаут
    
    if (receipt && receipt.status === 1) {
      console.log(`[DLE Proposals] Транзакция исполнения подтверждена: ${txHash}`);
      
      // Отправляем WebSocket уведомление
      const wsHub = require('../wsHub');
const { getSupportedChainIds } = require('../utils/networkLoader');
      wsHub.broadcastProposalExecuted(dleAddress, proposalId, txHash);
      
      res.json({
        success: true,
        data: {
          txHash: txHash,
          status: 'confirmed',
          receipt: receipt
        }
      });
    } else {
      res.json({
        success: false,
        error: 'Транзакция не подтверждена или провалилась'
      });
    }

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

// Декодировать данные предложения о добавлении модуля
router.post('/decode-proposal-data', async (req, res) => {
  try {
    const { transactionHash } = req.body;
    
    if (!transactionHash) {
      return res.status(400).json({
        success: false,
        error: 'Хеш транзакции обязателен'
      });
    }

    console.log(`[DLE Proposals] Декодирование данных транзакции: ${transactionHash}`);

    const rpcUrl = await rpcProviderService.getRpcUrlByChainId(11155111);
    if (!rpcUrl) {
      return res.status(500).json({
        success: false,
        error: 'RPC URL для Sepolia не найден'
      });
    }

    const provider = new ethers.JsonRpcProvider(rpcUrl);
    
    // Получаем данные транзакции
    const tx = await provider.getTransaction(transactionHash);
    if (!tx) {
      return res.status(404).json({
        success: false,
        error: 'Транзакция не найдена'
      });
    }

    // Декодируем данные транзакции
    const iface = new ethers.Interface([
      "function createAddModuleProposal(string memory _description, uint256 _duration, bytes32 _moduleId, address _moduleAddress, uint256 _chainId) external returns (uint256)"
    ]);

    try {
      const decoded = iface.parseTransaction({ data: tx.data });
      
      const proposalData = {
        description: decoded.args._description,
        duration: Number(decoded.args._duration),
        moduleId: decoded.args._moduleId,
        moduleAddress: decoded.args._moduleAddress,
        chainId: Number(decoded.args._chainId)
      };

      console.log(`[DLE Proposals] Декодированные данные:`, proposalData);

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

    } catch (decodeError) {
      console.log(`[DLE Proposals] Ошибка декодирования:`, decodeError.message);
      res.status(400).json({
        success: false,
        error: 'Не удалось декодировать данные транзакции: ' + decodeError.message
      });
    }

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

// Поиск предложения по transaction hash
router.post('/find-proposal-by-tx', async (req, res) => {
  try {
    const { transactionHash, dleAddress } = req.body;
    
    if (!transactionHash || !dleAddress) {
      return res.status(400).json({
        success: false,
        error: 'transactionHash и dleAddress обязательны'
      });
    }

    console.log(`[DLE Proposals] Поиск предложения по транзакции: ${transactionHash} для DLE: ${dleAddress}`);

    // Получаем поддерживаемые сети DLE
    let supportedChains = [];
    try {
      const candidateChainIds = await getSupportedChainIds();
      
      for (const cid of candidateChainIds) {
        try {
          const url = await rpcProviderService.getRpcUrlByChainId(cid);
          if (!url) continue;
          const prov = new ethers.JsonRpcProvider(url);
          const code = await prov.getCode(dleAddress);
          if (code && code !== '0x') {
            supportedChains.push(cid);
          }
        } catch (_) {}
      }
      
      if (supportedChains.length === 0) {
        supportedChains = [11155111, 17000, 421614, 84532];
      }
    } catch (error) {
      supportedChains = [11155111, 17000, 421614, 84532];
    }

    // Ищем транзакцию во всех поддерживаемых сетях
    for (const chainId of supportedChains) {
      try {
        const rpcUrl = await rpcProviderService.getRpcUrlByChainId(chainId);
        if (!rpcUrl) continue;

        const provider = new ethers.JsonRpcProvider(rpcUrl);
        
        // Получаем receipt транзакции
        const receipt = await provider.getTransactionReceipt(transactionHash);
        if (!receipt) {
          console.log(`[DLE Proposals] Транзакция ${transactionHash} не найдена в сети ${chainId}`);
          continue;
        }

        console.log(`[DLE Proposals] Транзакция найдена в сети ${chainId}, блок: ${receipt.blockNumber}`);

        // Ищем событие ProposalCreated в логах транзакции
        const dleAbi = [
          "event ProposalCreated(uint256 proposalId, address initiator, string description)"
        ];
        const dle = new ethers.Contract(dleAddress, dleAbi, provider);
        
        const iface = new ethers.Interface(dleAbi);
        const proposalCreatedTopic = iface.getEvent('ProposalCreated').topicHash;

        for (const log of receipt.logs) {
          if (log.address.toLowerCase() !== dleAddress.toLowerCase()) continue;
          if (log.topics[0] !== proposalCreatedTopic) continue;

          try {
            const parsedLog = iface.parseLog(log);
            const proposalId = parsedLog.args.proposalId;
            
            console.log(`[DLE Proposals] ✅ Найдено предложение ID: ${proposalId} в сети ${chainId}`);

            // Получаем полную информацию о предложении
            const fullDleAbi = [
              "function getProposalState(uint256 _proposalId) external view returns (uint8 state)",
              "function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
              "function getProposalSummary(uint256 _proposalId) external view returns (uint256 id, string memory description, uint256 forVotes, uint256 againstVotes, bool executed, bool canceled, uint256 deadline, address initiator, uint256 governanceChainId, uint256 snapshotTimepoint, uint256[] memory targetChains)"
            ];
            const fullDle = new ethers.Contract(dleAddress, fullDleAbi, provider);
            
            const proposalState = await fullDle.getProposalState(proposalId);
            const result = await fullDle.checkProposalResult(proposalId);
            const proposalData = await fullDle.getProposalSummary(proposalId);

            return res.json({
              success: true,
              data: {
                proposalId: Number(proposalId),
                chainId: chainId,
                description: parsedLog.args.description,
                initiator: parsedLog.args.initiator,
                transactionHash: transactionHash,
                blockNumber: receipt.blockNumber,
                state: Number(proposalState),
                isPassed: result.passed,
                quorumReached: result.quorumReached,
                forVotes: Number(proposalData.forVotes),
                againstVotes: Number(proposalData.againstVotes),
                executed: proposalData.executed,
                canceled: proposalData.canceled,
                deadline: Number(proposalData.deadline)
              }
            });
          } catch (parseError) {
            console.log(`[DLE Proposals] Ошибка парсинга лога:`, parseError.message);
          }
        }
      } catch (error) {
        console.log(`[DLE Proposals] Ошибка поиска в сети ${chainId}:`, error.message);
        continue;
      }
    }

    return res.status(404).json({
      success: false,
      error: 'Предложение не найдено по данной транзакции'
    });

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

module.exports = router;
