// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;

import { Test } from "forge-std/Test.sol";
import {
    CheckGelatoLow,
    IGelatoTreasury
} from "../periphery/drippie/dripchecks/CheckGelatoLow.sol";

/// @title  MockGelatoTreasury
/// @notice Mocks the Gelato treasury for testing purposes. Allows arbitrary
///        setting of user balances.
contract MockGelatoTreasury is IGelatoTreasury {
    mapping(address => mapping(address => uint256)) private tokenBalances;

    function setTokenBalance(
        address _user,
        address _token,
        uint256 _balance
    ) external {
        tokenBalances[_token][_user] = _balance;
    }

    function userTokenBalance(address _user, address _token) external view returns (uint256) {
        return tokenBalances[_token][_user];
    }
}

/// @title  CheckGelatoLowTest
/// @notice Tests the CheckBalanceHigh contract via fuzzing both the success case
///         and the failure case.
contract CheckGelatoLowTest is Test {
    /// @notice An instance of the CheckGelatoLow contract.
    CheckGelatoLow c;

    /// @notice An instance of the MockGelatoTreasury contract.
    MockGelatoTreasury gelato;

    /// @notice The account Gelato uses to represent ether
    address internal constant eth = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;

    /// @notice Deploy the `CheckGelatoLow` and `MockGelatoTreasury` contracts.
    function setUp() external {
        c = new CheckGelatoLow();
        gelato = new MockGelatoTreasury();
    }

    /// @notice Fuzz the `check` function and assert that it always returns true
    ///         when the user's balance in the treasury is less than the threshold.
    function testFuzz_check_succeeds(uint256 _threshold, address _recipient) external {
        CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
            treasury: address(gelato),
            threshold: _threshold,
            recipient: _recipient
        });

        vm.assume(gelato.userTokenBalance(_recipient, eth) < _threshold);

        assertEq(c.check(abi.encode(p)), true);
    }

    /// @notice Fuzz the `check` function and assert that it always returns false
    ///         when the user's balance in the treasury is greater than or equal
    ///         to the threshold.
    function testFuzz_check_highBalance_fails(uint256 _threshold, address _recipient) external {
        CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
            treasury: address(gelato),
            threshold: _threshold,
            recipient: _recipient
        });

        gelato.setTokenBalance(_recipient, eth, _threshold);

        assertEq(c.check(abi.encode(p)), false);
    }
}
