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

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

contract AggregatorFuzzTest is Test {
    Aggregator aggregator;
    address admin;
    address transmitter;
    address user;
    
    function setUp() public {
        admin = address(1);
        transmitter = address(2);
        user = address(3);
        
        vm.prank(admin);
        aggregator = new Aggregator(
            "ETH/USD Price Feed",
            admin,
            60,  // heartbeat: 60 seconds
            50   // deviationThreshold: 0.5% (50 basis points)
        );
        
        vm.prank(admin);
        aggregator.addTransmitter(transmitter);
    }
    
    function testFuzzUpdateAnswer(uint256 answer) public {
        vm.assume(answer > 0);
        vm.assume(answer < type(uint256).max / 100000000); // Prevent overflow
        
        vm.prank(transmitter);
        aggregator.updateAnswer(answer);
        
        // forge-lint: disable-next-line(unsafe-typecast)
        // casting to 'int256' is safe because answer is constrained to prevent overflow
        assertEq(aggregator.latestAnswer(), int256(answer));
    }
    
    function testFuzzMultipleUpdates(uint256[10] memory answers) public {
        uint256 lastAnswer = 0;
        for (uint i = 0; i < answers.length; i++) {
            vm.assume(answers[i] > 0);
            vm.assume(answers[i] < type(uint256).max / 100000000);
            
            // Ensure sufficient deviation (0.5% = 50 basis points) to trigger update
            // If this is the first update or deviation is >= 0.5%, it will update
            if (lastAnswer == 0 || 
                (answers[i] > lastAnswer ? ((answers[i] - lastAnswer) * 10000) / lastAnswer >= 50 :
                 ((lastAnswer - answers[i]) * 10000) / lastAnswer >= 50)) {
                vm.prank(transmitter);
                aggregator.updateAnswer(answers[i]);
                
                // forge-lint: disable-next-line(unsafe-typecast)
                // casting to 'int256' is safe because answers[i] is constrained to prevent overflow
                assertEq(aggregator.latestAnswer(), int256(answers[i]));
                lastAnswer = answers[i];
            } else {
                // If deviation is too small, the answer won't update
                // Skip this iteration or use a different answer
                continue;
            }
        }
    }
    
    function testFuzzAddTransmitter(address newTransmitter) public {
        vm.assume(newTransmitter != address(0));
        vm.assume(newTransmitter != admin);
        vm.assume(newTransmitter != transmitter);
        
        vm.prank(admin);
        aggregator.addTransmitter(newTransmitter);
        
        assertTrue(aggregator.isTransmitter(newTransmitter));
    }
    
    function testFuzzSetHeartbeat(uint256 heartbeat) public {
        vm.assume(heartbeat > 0);
        vm.assume(heartbeat < type(uint256).max / 2);
        
        vm.prank(admin);
        aggregator.updateHeartbeat(heartbeat);
        
        assertEq(aggregator.heartbeat(), heartbeat);
    }
    
    function testFuzzSetDeviationThreshold(uint256 threshold) public {
        vm.assume(threshold <= 10000); // Max 100%
        
        vm.prank(admin);
        aggregator.updateDeviationThreshold(threshold);
        
        assertEq(aggregator.deviationThreshold(), threshold);
    }
}

