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

import {Test} from "forge-std/Test.sol";
import {InstrumentRegistry} from "../../contracts/hybx-omnl/InstrumentRegistry.sol";
import {ReserveCommitmentStore} from "../../contracts/hybx-omnl/ReserveCommitmentStore.sol";
import {OMNLCircuitBreaker} from "../../contracts/hybx-omnl/OMNLCircuitBreaker.sol";
import {ComplianceCore} from "../../contracts/hybx-omnl/ComplianceCore.sol";
import {MockMintableToken} from "../dbis/MockMintableToken.sol";

contract ComplianceCoreTest is Test {
    InstrumentRegistry public registry;
    ReserveCommitmentStore public reserveStore;
    OMNLCircuitBreaker public breakers;
    ComplianceCore public core;

    MockMintableToken public m0;
    MockMintableToken public m1;

    bytes32 public constant LINE = keccak256("TEST_USD");

    function setUp() public {
        address admin = address(this);
        registry = new InstrumentRegistry(admin);
        reserveStore = new ReserveCommitmentStore(admin);
        breakers = new OMNLCircuitBreaker(admin);
        core = new ComplianceCore(address(registry), address(reserveStore), address(breakers));

        m0 = new MockMintableToken("M0", "M0", 6, admin);
        m1 = new MockMintableToken("M1", "M1", 6, admin);

        registry.registerLine(LINE, address(m0), address(m1), 6, 840, false);

        reserveStore.commitReserve(LINE, 130e6, block.timestamp + 1 days, bytes32(uint256(1)), bytes32(uint256(42)));

        m0.mint(address(this), 100e6);
        m1.mint(address(this), 400e6);
    }

    function testGetCompliance() public view {
        (
            uint256 s0,
            uint256 s1,
            uint256 r,
            ,
            bytes32 evidenceHash,
            bytes32 merkleRoot,
            uint256 minR,
            uint256 maxS1,
            bool m0Ok,
            bool m1Ok,
            bool stale,
            bool policyOk,
            bool operational,
            bool reportingCompliant
        ) = core.getCompliance(LINE);

        assertEq(s0, 100e6);
        assertEq(s1, 400e6);
        assertEq(r, 130e6);
        assertEq(evidenceHash, bytes32(uint256(1)));
        assertEq(merkleRoot, bytes32(uint256(42)));
        assertEq(minR, 120e6);
        assertEq(maxS1, 500e6);
        assertTrue(m0Ok);
        assertTrue(m1Ok);
        assertFalse(stale);
        assertTrue(policyOk);
        assertTrue(operational);
        assertTrue(reportingCompliant);
    }

    function testReportingFalseWhenStale() public {
        vm.warp(block.timestamp + 2 days);
        (,,,,,,,,,, bool stale,,, bool reportingCompliant) = core.getCompliance(LINE);
        assertTrue(stale);
        assertFalse(reportingCompliant);
    }

    function testAssertMintM1FailsOverCap() public {
        vm.expectRevert(abi.encodeWithSelector(ComplianceCore.ComplianceBlocked.selector, LINE, "m1_cap"));
        core.assertCanMintM1(LINE, 101e6);
    }

    function testAssertMintM0FailsInsufficientR() public {
        vm.expectRevert(abi.encodeWithSelector(ComplianceCore.ComplianceBlocked.selector, LINE, "m0_backing"));
        core.assertCanMintM0(LINE, 11e6);
    }
}
