// SPDX-License-Identifier: PROPRIETARY AND MIT
// Copyright (c) 2024-2026 Тарабанов Александр Викторович
// All rights reserved.

pragma solidity ^0.8.20;

interface IDLEReader {
    // Структуры из основного контракта
    struct DLEInfo {
        string name;
        string symbol;
        string location;
        string coordinates;
        uint256 jurisdiction;
        string[] okvedCodes;
        uint256 kpp;
        uint256 creationTimestamp;
        bool isActive;
    }

    struct Proposal {
        uint256 id;
        string description;
        uint256 forVotes;
        uint256 againstVotes;
        bool executed;
        bool canceled;
        uint256 deadline;
        address initiator;
        bytes operation;
        uint256 governanceChainId;
        uint256[] targetChains;
        uint256 snapshotTimepoint;
    }

    // Основные функции чтения
    function getDLEInfo() external view returns (DLEInfo memory);
    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
    );
    function allProposalIds(uint256) external view returns (uint256);
    function supportedChainIds(uint256) external view returns (uint256);
    function quorumPercentage() external view returns (uint256);
    function currentChainId() external view returns (uint256);
    function totalSupply() external view returns (uint256);
    function getPastTotalSupply(uint256) external view returns (uint256);
    function getPastVotes(address, uint256) external view returns (uint256);
    function checkProposalResult(uint256) external view returns (bool, bool);
    function getProposalState(uint256) external view returns (uint8);
    function balanceOf(address) external view returns (uint256);
    function isChainSupported(uint256) external view returns (bool);
    function isModuleActive(bytes32) external view returns (bool);
    function getModuleAddress(bytes32) external view returns (address);
}

/**
 * @title DLEReader
 * @dev Read-only контракт для API функций DLE
 * 
 * БЕЗОПАСНОСТЬ:
 * - Только чтение данных (view/pure функции)
 * - Не изменяет состояние основного контракта
 * - Можно безопасно обновлять независимо от DLE
 * - Нет доступа к приватным данным
 */
contract DLEReader {
    
    address public immutable dleContract;
    
    constructor(address _dleContract) {
        require(_dleContract != address(0), "DLE contract cannot be zero");
        require(_dleContract.code.length > 0, "DLE contract must exist");
        dleContract = _dleContract;
    }
    
    // ===== АГРЕГИРОВАННЫЕ ДАННЫЕ =====
    
    /**
     * @dev Получить полную сводку по предложению
     */
    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,
        uint8 state,
        bool passed,
        bool quorumReached
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        // Получаем основные данные предложения
        (
            id,
            description,
            forVotes,
            againstVotes,
            executed,
            canceled,
            deadline,
            initiator,
            ,  // operation не нужна для сводки
            governanceChainId,
            snapshotTimepoint
        ) = dle.proposals(_proposalId);
        
        // Получаем дополнительные данные
        state = dle.getProposalState(_proposalId);
        (passed, quorumReached) = dle.checkProposalResult(_proposalId);
        
        // TODO: targetChains требует отдельной функции в основном контракте
        targetChains = new uint256[](0);
    }
    
    /**
     * @dev Получить параметры governance
     */
    function getGovernanceParams() external view returns (
        uint256 quorumPct,
        uint256 chainId,
        uint256 supportedCount,
        uint256 totalSupply,
        uint256 proposalsCount
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        quorumPct = dle.quorumPercentage();
        chainId = dle.currentChainId();
        totalSupply = dle.totalSupply();
        
        // Считаем поддерживаемые сети
        supportedCount = 0;
        for (uint256 i = 0; i < 50; i++) { // Ограничиваем итерации
            try dle.supportedChainIds(i) returns (uint256) {
                supportedCount++;
            } catch {
                break;
            }
        }
        
        // Считаем предложения
        proposalsCount = 0;
        for (uint256 i = 0; i < 1000; i++) { // Ограничиваем итерации
            try dle.allProposalIds(i) returns (uint256) {
                proposalsCount++;
            } catch {
                break;
            }
        }
    }
    
    /**
     * @dev Получить список поддерживаемых сетей
     */
    function listSupportedChains() external view returns (uint256[] memory chains) {
        IDLEReader dle = IDLEReader(dleContract);
        
        // Сначала считаем количество
        uint256 count = 0;
        for (uint256 i = 0; i < 50; i++) {
            try dle.supportedChainIds(i) returns (uint256) {
                count++;
            } catch {
                break;
            }
        }
        
        // Затем заполняем массив
        chains = new uint256[](count);
        for (uint256 i = 0; i < count; i++) {
            chains[i] = dle.supportedChainIds(i);
        }
    }
    
    /**
     * @dev Получить список предложений с пагинацией
     */
    function listProposals(uint256 offset, uint256 limit) external view returns (
        uint256[] memory proposalIds,
        uint256 total
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        // Считаем общее количество
        total = 0;
        for (uint256 i = 0; i < 10000; i++) { // Увеличиваем лимит для предложений
            try dle.allProposalIds(i) returns (uint256) {
                total++;
            } catch {
                break;
            }
        }
        
        // Проверяем границы
        if (offset >= total) {
            return (new uint256[](0), total);
        }
        
        uint256 end = offset + limit;
        if (end > total) end = total;
        
        // Заполняем страницу
        proposalIds = new uint256[](end - offset);
        for (uint256 i = offset; i < end; i++) {
            proposalIds[i - offset] = dle.allProposalIds(i);
        }
    }
    
    /**
     * @dev Получить голосующую силу на определённый момент времени
     */
    function getVotingPowerAt(address voter, uint256 timepoint) external view returns (uint256) {
        return IDLEReader(dleContract).getPastVotes(voter, timepoint);
    }
    
    /**
     * @dev Получить размер кворума на определённый момент времени
     */
    function getQuorumAt(uint256 timepoint) external view returns (uint256) {
        IDLEReader dle = IDLEReader(dleContract);
        uint256 supply = dle.getPastTotalSupply(timepoint);
        uint256 quorumPct = dle.quorumPercentage();
        return (supply * quorumPct) / 100;
    }
    
    /**
     * @dev Получить детали голосования по предложению
     */
    function getProposalVotes(uint256 _proposalId) external view returns (
        uint256 forVotes,
        uint256 againstVotes,
        uint256 totalVotes,
        uint256 quorumRequired,
        uint256 quorumCurrent,
        bool quorumReached
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        // Получаем основные данные предложения
        uint256 snapshotTimepoint;
        (
            ,  // id
            ,  // description
            forVotes,
            againstVotes,
            ,  // executed
            ,  // canceled
            ,  // deadline
            ,  // initiator
            ,  // operation
            ,  // governanceChainId
            snapshotTimepoint
        ) = dle.proposals(_proposalId);
        
        totalVotes = forVotes + againstVotes;
        
        // Вычисляем кворум
        uint256 supply = dle.getPastTotalSupply(snapshotTimepoint);
        uint256 quorumPct = dle.quorumPercentage();
        quorumRequired = (supply * quorumPct) / 100;
        quorumCurrent = totalVotes;
        quorumReached = totalVotes >= quorumRequired;
    }
    
    /**
     * @dev Получить статистику по адресу
     */
    function getAddressStats(address user) external view returns (
        uint256 tokenBalance,
        uint256 currentVotingPower,
        uint256 delegatedTo,
        bool hasTokens
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        tokenBalance = dle.balanceOf(user);
        currentVotingPower = dle.getPastVotes(user, block.number - 1);
        hasTokens = tokenBalance > 0;
        
        // delegatedTo требует дополнительных функций в основном контракте
        delegatedTo = 0; // Placeholder
    }
    
    /**
     * @dev Получить информацию о модулях
     */
    function getModulesInfo(bytes32[] memory moduleIds) external view returns (
        address[] memory addresses,
        bool[] memory active
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        addresses = new address[](moduleIds.length);
        active = new bool[](moduleIds.length);
        
        for (uint256 i = 0; i < moduleIds.length; i++) {
            addresses[i] = dle.getModuleAddress(moduleIds[i]);
            active[i] = dle.isModuleActive(moduleIds[i]);
        }
    }
    
    /**
     * @dev Получить состояние DLE
     */
    function getDLEStatus() external view returns (
        IDLEReader.DLEInfo memory info,
        uint256 totalSupply,
        uint256 currentChain,
        uint256 quorumPct,
        uint256 totalProposals,
        uint256 supportedChains
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        info = dle.getDLEInfo();
        totalSupply = dle.totalSupply();
        currentChain = dle.currentChainId();
        quorumPct = dle.quorumPercentage();
        
        // Считаем предложения и сети
        (,, supportedChains, totalSupply, totalProposals) = this.getGovernanceParams();
    }
    
    /**
     * @dev Batch получение состояний предложений
     */
    function getProposalStates(uint256[] memory proposalIds) external view returns (
        uint8[] memory states,
        bool[] memory passed,
        bool[] memory quorumReached
    ) {
        IDLEReader dle = IDLEReader(dleContract);
        
        states = new uint8[](proposalIds.length);
        passed = new bool[](proposalIds.length);
        quorumReached = new bool[](proposalIds.length);
        
        for (uint256 i = 0; i < proposalIds.length; i++) {
            states[i] = dle.getProposalState(proposalIds[i]);
            (passed[i], quorumReached[i]) = dle.checkProposalResult(proposalIds[i]);
        }
    }
}
