pragma solidity 0.8.20;

import {Test} from "forge-std/Test.sol";

import {Gatekeeper} from "../../src/Gatekeeper.sol";

contract GatekeeperMetadataTest is Test {
    address constant ALICE        = 0x0000000000000000000000000000000000000001;
    uint256 constant INIT_AMOUNT  = 69 * 1e18;
    uint256 constant INIT_GHOSTED = type(uint104).max / 2;
    uint256 constant EXISTENTIAL  = 0;
    uint48  constant DEPLOYED_AT  = 1337;
    uint104 constant AMOUNT_IN    = 69;
    uint104 constant AMOUNT_OUT   = 420;

    Gatekeeper gatekeeper;

    function setUp() public {
        gatekeeper = new Gatekeeper(ALICE, INIT_GHOSTED, EXISTENTIAL, DEPLOYED_AT, AMOUNT_IN, AMOUNT_OUT);
    }

    function test_correctMetadataInitialization() public view {
        Gatekeeper.GatekeeperMetadata memory metadata = gatekeeper.metadata();
        assertEq(metadata.deployedAt, DEPLOYED_AT);
        assertEq(metadata.amountIn, AMOUNT_IN);
        assertEq(metadata.amountOut, AMOUNT_OUT);
        assertEq(gatekeeper.ghostedSupply(), INIT_GHOSTED);
    }

    function test_historicalAmountsOnlyIncrease(uint256 ghostAmount) public {
        vm.assume(ghostAmount > 0 && ghostAmount < INIT_GHOSTED / 2);
        bytes32 receiver = bytes32(abi.encodePacked(ALICE));
        uint256 ghostedSupply = gatekeeper.ghostedSupply();

        Gatekeeper.GatekeeperMetadata memory metadata = gatekeeper.metadata();
        uint104 amountIn = metadata.amountIn;
        uint104 amountOut = metadata.amountOut;

        if (ghostAmount % 2 == 0) {
            vm.prank(ALICE);
            gatekeeper.ghost(receiver, ghostAmount);
            amountIn += uint104(ghostAmount); // forge-lint: disable-line(unsafe-typecast)
            ghostedSupply += ghostAmount;
        } else {
            vm.expectRevert();
            vm.prank(ALICE);
            gatekeeper.materialize(ALICE, ghostAmount, 0, 0);
        }

        Gatekeeper.GatekeeperMetadata memory newMetadata = gatekeeper.metadata();
        assertEq(newMetadata.amountIn, amountIn);
        assertEq(newMetadata.amountOut, amountOut);
        assertEq(gatekeeper.ghostedSupply(), ghostedSupply);
    }

}
