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

import {Test, console} from "forge-std/Test.sol";
import {Multicall} from "../contracts/utils/Multicall.sol";
import {WETH} from "../contracts/tokens/WETH.sol";

contract MulticallTest is Test {
    Multicall public multicall;
    WETH public weth;
    
    function setUp() public {
        multicall = new Multicall();
        weth = new WETH();
        vm.deal(address(this), 10 ether);
    }
    
    function testAggregate() public {
        weth.deposit{value: 1 ether}();
        
        Multicall.Call[] memory calls = new Multicall.Call[](2);
        calls[0] = Multicall.Call({
            target: address(weth),
            callData: abi.encodeWithSignature("totalSupply()")
        });
        calls[1] = Multicall.Call({
            target: address(weth),
            callData: abi.encodeWithSignature("balanceOf(address)", address(this))
        });
        
        bytes[] memory results = multicall.aggregate(calls);
        
        uint256 totalSupply = abi.decode(results[0], (uint256));
        uint256 balance = abi.decode(results[1], (uint256));
        
        assertEq(totalSupply, 1 ether);
        assertEq(balance, 1 ether);
    }
    
    function testTryAggregate() public {
        weth.deposit{value: 1 ether}();
        
        Multicall.Call[] memory calls = new Multicall.Call[](2);
        calls[0] = Multicall.Call({
            target: address(weth),
            callData: abi.encodeWithSignature("totalSupply()")
        });
        // Use a contract that will revert (WETH with invalid function call)
        calls[1] = Multicall.Call({
            target: address(weth),
            callData: abi.encodeWithSignature("invalidFunction()")
        });
        
        Multicall.Result[] memory results = multicall.tryAggregate(false, calls);
        
        assertTrue(results[0].success);
        assertFalse(results[1].success);
    }
    
    function testGetChainId() public {
        uint256 chainId = multicall.getChainId();
        assertEq(chainId, block.chainid);
    }
    
    function testGetCurrentBlockNumber() public {
        uint256 blockNumber = multicall.getCurrentBlockNumber();
        assertEq(blockNumber, block.number);
    }
}

