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

import "forge-std/Test.sol";
import "../src/Governance.sol";

contract GovernanceTest is Test {
    Governance governance;

    address admin = address(1);
    address member1 = address(10);
    address member2 = address(11);
    address member3 = address(12);
    address member4 = address(13);
    address member5 = address(14);
    address target = address(99);

    function setUp() public {
        vm.startPrank(admin);

        address[] memory members = new address[](5);
        members[0] = member1;
        members[1] = member2;
        members[2] = member3;
        members[3] = member4;
        members[4] = member5;

        governance = new Governance();
        governance.initialize(members, admin);

        vm.stopPrank();
    }

    function test_ProposeCreatesProposal() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "0x1234", "Test proposal");

        (
            address pTarget,
            uint256 executeAfter,
            uint256 approvalCount,
            bool executed,
            bool emergency,
            address proposer,
            string memory description
        ) = governance.getProposal(proposalId);

        assertEq(pTarget, target);
        assertEq(approvalCount, 1); // 提案者自动审批
        assertFalse(executed);
        assertFalse(emergency);
        assertEq(proposer, member1);
        assertEq(description, "Test proposal");
        assertEq(executeAfter, block.timestamp + 48 hours);
    }

    function test_EmergencyProposalShortTimelock() public {
        vm.prank(member1);
        uint256 proposalId = governance.proposeEmergency(target, "0x1234", "Emergency");

        (, uint256 executeAfter,,, bool emergency,,) = governance.getProposal(proposalId);
        assertTrue(emergency);
        assertEq(executeAfter, block.timestamp + 4 hours);
    }

    function test_ApproveAndExecute() public {
        // 提案
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        // member2 和 member3 审批 (共 3 个)
        vm.prank(member2);
        governance.approve(proposalId);
        vm.prank(member3);
        governance.approve(proposalId);

        (,, uint256 approvalCount,,,,) = governance.getProposal(proposalId);
        assertEq(approvalCount, 3);

        // 快进 48h
        vm.warp(block.timestamp + 48 hours);

        // 构造一个可执行的target
        // 由于 target 没有代码，call 会成功
        vm.prank(member1);
        governance.execute(proposalId);

        (,,, bool executed,,,) = governance.getProposal(proposalId);
        assertTrue(executed);
    }

    function test_ExecuteNotEnoughApprovalsReverts() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        // 只有 1 个审批（提案者自己）
        vm.warp(block.timestamp + 48 hours);

        vm.prank(member1);
        vm.expectRevert("Governance: not enough approvals");
        governance.execute(proposalId);
    }

    function test_ExecuteTimelockNotExpiredReverts() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        vm.prank(member2);
        governance.approve(proposalId);
        vm.prank(member3);
        governance.approve(proposalId);

        // 不快进时间
        vm.prank(member1);
        vm.expectRevert("Governance: timelock not expired");
        governance.execute(proposalId);
    }

    function test_DoubleApproveReverts() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        vm.prank(member1);
        vm.expectRevert("Governance: already approved");
        governance.approve(proposalId);
    }

    function test_CancelByProposer() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        vm.prank(member1);
        governance.cancel(proposalId);

        (,,, bool executed,,,) = governance.getProposal(proposalId);
        assertTrue(executed); // 标记为已执行以阻止未来执行
    }

    function test_CancelByNonProposerReverts() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        vm.prank(member2);
        vm.expectRevert("Governance: not authorized");
        governance.cancel(proposalId);
    }

    function test_HasApproved() public {
        vm.prank(member1);
        uint256 proposalId = governance.propose(target, "", "Test");

        assertTrue(governance.hasApproved(proposalId, member1));
        assertFalse(governance.hasApproved(proposalId, member2));
    }

    function test_OnlyMultisigCanPropose() public {
        address random = address(888);
        vm.prank(random);
        vm.expectRevert();
        governance.propose(target, "", "Test");
    }

    function test_RecordPreviousImplementation() public {
        address proxy = address(100);
        address impl = address(101);

        vm.prank(member1);
        governance.recordPreviousImplementation(proxy, impl);

        assertEq(governance.previousImplementations(proxy), impl);
    }
}
