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

import "forge-std/Test.sol";
import "../src/Compliance.sol";
import "../src/interfaces/ICoupon.sol";

contract ComplianceTest is Test {
    Compliance compliance;

    address admin = address(1);
    address user1 = address(2);
    address user2 = address(3);
    address officer = address(4);

    function setUp() public {
        vm.startPrank(admin);
        compliance = new Compliance();
        compliance.initialize(admin);
        compliance.grantRole(keccak256("COMPLIANCE_OFFICER_ROLE"), officer);
        vm.stopPrank();
    }

    // === OFAC ===

    function test_AddToBlacklist() public {
        vm.prank(officer);
        compliance.addToBlacklist(user1, "OFAC SDN");
        assertTrue(compliance.isBlacklisted(user1));
    }

    function test_RemoveFromBlacklist() public {
        vm.prank(officer);
        compliance.addToBlacklist(user1, "OFAC SDN");

        vm.prank(admin);
        compliance.removeFromBlacklist(user1);
        assertFalse(compliance.isBlacklisted(user1));
    }

    function test_RemoveFromBlacklistOnlyGovernance() public {
        vm.prank(officer);
        compliance.addToBlacklist(user1, "OFAC SDN");

        vm.prank(officer);
        vm.expectRevert();
        compliance.removeFromBlacklist(user1);
    }

    // === KYC ===

    function test_SetKycLevel() public {
        vm.prank(admin);
        compliance.setKycLevel(user1, 2);
        assertEq(compliance.getKycLevel(user1), 2);
    }

    function test_InvalidKycLevelReverts() public {
        vm.prank(admin);
        vm.expectRevert("Compliance: invalid KYC level");
        compliance.setKycLevel(user1, 4);
    }

    function test_RequireKycLevelSuccess() public view {
        // L0 默认
        compliance.requireKycLevel(user1, 0);
    }

    function test_RequireKycLevelFails() public {
        vm.expectRevert("Compliance: insufficient KYC level");
        compliance.requireKycLevel(user1, 1);
    }

    function test_BatchSetKycLevel() public {
        address[] memory accounts = new address[](2);
        accounts[0] = user1;
        accounts[1] = user2;
        uint8[] memory levels = new uint8[](2);
        levels[0] = 1;
        levels[1] = 2;

        vm.prank(admin);
        compliance.batchSetKycLevel(accounts, levels);

        assertEq(compliance.getKycLevel(user1), 1);
        assertEq(compliance.getKycLevel(user2), 2);
    }

    // === Freeze ===

    function test_FreezeAccount() public {
        vm.prank(admin);
        compliance.freezeAccount(user1);
        assertTrue(compliance.isFrozen(user1));
    }

    function test_UnfreezeAccount() public {
        vm.prank(admin);
        compliance.freezeAccount(user1);
        vm.prank(admin);
        compliance.unfreezeAccount(user1);
        assertFalse(compliance.isFrozen(user1));
    }

    // === Travel Rule ===

    function test_RecordTravelRule() public {
        vm.prank(officer);
        compliance.recordTravelRule(user1, user2, keccak256("sender"), keccak256("receiver"));
        assertTrue(compliance.hasTravelRuleRecord(user1, user2));
    }

    // === Pre-Trade Check ===

    function test_PreTradeCheckUtilityRequiresKycL1() public {
        // 无 KYC
        vm.expectRevert("Compliance: buyer needs KYC L1 for Utility");
        compliance.preTradeCheck(user1, user2, 100e6, ICoupon.CouponType.Utility);
    }

    function test_PreTradeCheckSecurityRequiresKycL2() public {
        vm.startPrank(admin);
        compliance.setKycLevel(user1, 1);
        compliance.setKycLevel(user2, 1);
        vm.stopPrank();

        vm.expectRevert("Compliance: buyer needs KYC L2 for Security");
        compliance.preTradeCheck(user1, user2, 100e6, ICoupon.CouponType.Security);
    }

    function test_PreTradeCheckLargeTradeRequiresKycL2() public {
        vm.startPrank(admin);
        compliance.setKycLevel(user1, 1);
        compliance.setKycLevel(user2, 1);
        vm.stopPrank();

        vm.expectRevert("Compliance: buyer needs KYC L2 for large trade");
        compliance.preTradeCheck(user1, user2, 10000e6, ICoupon.CouponType.Utility);
    }

    function test_PreTradeCheckBlacklistedReverts() public {
        vm.startPrank(admin);
        compliance.setKycLevel(user1, 2);
        compliance.setKycLevel(user2, 2);
        vm.stopPrank();

        vm.prank(officer);
        compliance.addToBlacklist(user1, "OFAC");

        vm.expectRevert("Compliance: buyer blacklisted");
        compliance.preTradeCheck(user1, user2, 100e6, ICoupon.CouponType.Utility);
    }

    function test_PreTradeCheckFrozenReverts() public {
        vm.startPrank(admin);
        compliance.setKycLevel(user1, 2);
        compliance.setKycLevel(user2, 2);
        compliance.freezeAccount(user2);
        vm.stopPrank();

        vm.expectRevert("Compliance: seller frozen");
        compliance.preTradeCheck(user1, user2, 100e6, ICoupon.CouponType.Utility);
    }

    // === P2P Check ===

    function test_P2pCheckRequiresTravelRule() public {
        vm.startPrank(admin);
        compliance.setKycLevel(user1, 2);
        compliance.setKycLevel(user2, 2);
        vm.stopPrank();

        vm.expectRevert("Compliance: Travel Rule data required");
        compliance.p2pComplianceCheck(user1, user2, 5000e6);
    }

    function test_P2pCheckWithTravelRuleSuccess() public {
        vm.startPrank(admin);
        compliance.setKycLevel(user1, 2);
        compliance.setKycLevel(user2, 2);
        vm.stopPrank();

        vm.prank(officer);
        compliance.recordTravelRule(user1, user2, keccak256("s"), keccak256("r"));

        // 不应 revert
        compliance.p2pComplianceCheck(user1, user2, 5000e6);
    }

    function test_P2pCheckBelowThresholdNoTravelRule() public {
        // $2,999 无需 Travel Rule
        compliance.p2pComplianceCheck(user1, user2, 2999e6);
    }
}
