// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";

/// @title Governance — 治理合约
/// @notice 3/5 多签 + 48h 时间锁 + 紧急 4h 通道 + 合约升级回滚
/// @dev 管理所有合约的升级、参数调整、紧急冻结
contract Governance is Initializable, AccessControlUpgradeable {
    bytes32 public constant MULTISIG_ROLE = keccak256("MULTISIG_ROLE");

    uint256 public constant REQUIRED_SIGNATURES = 3;        // 3/5 多签
    uint256 public constant EMERGENCY_SIGNATURES = 4;       // 紧急需 4/5
    uint256 public constant TIMELOCK = 48 hours;             // 标准时间锁
    uint256 public constant EMERGENCY_TIMELOCK = 4 hours;    // 紧急时间锁

    uint256 public nextProposalId;

    struct Proposal {
        bytes callData;
        address target;
        uint256 executeAfter;
        uint256 approvalCount;
        bool executed;
        bool emergency;
        address proposer;
        string description;
        uint256 createdAt;
    }

    mapping(uint256 => Proposal) public proposals;
    mapping(uint256 => mapping(address => bool)) public approvals;

    // 合约升级回滚支持
    mapping(address => address) public previousImplementations;

    // --- Events ---
    event ProposalCreated(
        uint256 indexed proposalId,
        address indexed proposer,
        address target,
        bool emergency,
        string description
    );
    event ProposalApproved(uint256 indexed proposalId, address indexed approver, uint256 approvalCount);
    event ProposalExecuted(uint256 indexed proposalId, address indexed executor);
    event ProposalCancelled(uint256 indexed proposalId);
    event ContractRolledBack(address indexed proxy, address indexed previousImpl);
    event PreviousImplementationRecorded(address indexed proxy, address indexed impl);

    function initialize(address[] memory multisigMembers, address admin) external initializer {
        __AccessControl_init();

        _grantRole(DEFAULT_ADMIN_ROLE, admin);
        for (uint256 i = 0; i < multisigMembers.length; i++) {
            _grantRole(MULTISIG_ROLE, multisigMembers[i]);
        }
    }

    // ========================
    // 提案管理
    // ========================

    /// @notice 创建标准提案（48h 时间锁）
    function propose(
        address target,
        bytes calldata data,
        string calldata description
    ) external onlyRole(MULTISIG_ROLE) returns (uint256 proposalId) {
        proposalId = _createProposal(target, data, description, false);
    }

    /// @notice 创建紧急提案（4h 时间锁）
    function proposeEmergency(
        address target,
        bytes calldata data,
        string calldata description
    ) external onlyRole(MULTISIG_ROLE) returns (uint256 proposalId) {
        proposalId = _createProposal(target, data, description, true);
    }

    /// @notice 审批提案
    function approve(uint256 proposalId) external onlyRole(MULTISIG_ROLE) {
        Proposal storage p = proposals[proposalId];
        require(p.target != address(0), "Governance: proposal not found");
        require(!p.executed, "Governance: already executed");
        require(!approvals[proposalId][msg.sender], "Governance: already approved");

        approvals[proposalId][msg.sender] = true;
        p.approvalCount++;

        emit ProposalApproved(proposalId, msg.sender, p.approvalCount);
    }

    /// @notice 执行提案
    function execute(uint256 proposalId) external onlyRole(MULTISIG_ROLE) {
        Proposal storage p = proposals[proposalId];
        require(p.target != address(0), "Governance: proposal not found");
        require(!p.executed, "Governance: already executed");

        // 签名数量检查
        uint256 required = p.emergency ? EMERGENCY_SIGNATURES : REQUIRED_SIGNATURES;
        require(p.approvalCount >= required, "Governance: not enough approvals");

        // 时间锁检查
        require(block.timestamp >= p.executeAfter, "Governance: timelock not expired");

        p.executed = true;
        (bool success,) = p.target.call(p.callData);
        require(success, "Governance: execution failed");

        emit ProposalExecuted(proposalId, msg.sender);
    }

    /// @notice 取消提案（仅提案者或 Admin）
    function cancel(uint256 proposalId) external {
        Proposal storage p = proposals[proposalId];
        require(p.target != address(0), "Governance: proposal not found");
        require(!p.executed, "Governance: already executed");
        require(
            p.proposer == msg.sender || hasRole(DEFAULT_ADMIN_ROLE, msg.sender),
            "Governance: not authorized"
        );

        // 标记为已执行来阻止未来执行
        p.executed = true;
        emit ProposalCancelled(proposalId);
    }

    // ========================
    // 合约升级回滚
    // ========================

    /// @notice 升级时记录前一版本 Implementation 地址
    function recordPreviousImplementation(address proxy, address currentImpl)
        external
        onlyRole(MULTISIG_ROLE)
    {
        previousImplementations[proxy] = currentImpl;
        emit PreviousImplementationRecorded(proxy, currentImpl);
    }

    /// @notice 紧急回滚至上一版本（需 4/5 多签）
    /// @dev 通过紧急提案调用此方法
    function rollback(address proxy) external onlyRole(MULTISIG_ROLE) {
        address prevImpl = previousImplementations[proxy];
        require(prevImpl != address(0), "Governance: no previous version");

        // 调用 proxy 的 upgradeTo
        (bool success,) = proxy.call(
            abi.encodeWithSignature("upgradeTo(address)", prevImpl)
        );
        require(success, "Governance: rollback failed");

        emit ContractRolledBack(proxy, prevImpl);
    }

    // ========================
    // 查询
    // ========================

    /// @notice 查询提案详情
    function getProposal(uint256 proposalId) external view returns (
        address target,
        uint256 executeAfter,
        uint256 approvalCount,
        bool executed,
        bool emergency,
        address proposer,
        string memory description
    ) {
        Proposal storage p = proposals[proposalId];
        return (p.target, p.executeAfter, p.approvalCount, p.executed, p.emergency, p.proposer, p.description);
    }

    /// @notice 查询某地址是否已审批
    function hasApproved(uint256 proposalId, address member) external view returns (bool) {
        return approvals[proposalId][member];
    }

    // ========================
    // Internal
    // ========================

    function _createProposal(
        address target,
        bytes calldata data,
        string calldata description,
        bool emergency
    ) internal returns (uint256 proposalId) {
        require(target != address(0), "Governance: zero target");

        proposalId = nextProposalId++;
        uint256 timelock = emergency ? EMERGENCY_TIMELOCK : TIMELOCK;

        proposals[proposalId] = Proposal({
            callData: data,
            target: target,
            executeAfter: block.timestamp + timelock,
            approvalCount: 1, // 提案者自动审批
            executed: false,
            emergency: emergency,
            proposer: msg.sender,
            description: description,
            createdAt: block.timestamp
        });

        approvals[proposalId][msg.sender] = true;

        emit ProposalCreated(proposalId, msg.sender, target, emergency, description);
    }
}
