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

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

contract EvidenceRegistryV3Test is Test {
    uint256 internal constant ATTESTER_KEY = 0xA771;
    address internal owner = address(0xBEEF);
    address internal attester = vm.addr(ATTESTER_KEY);
    EvidenceRegistryV3 internal evidence;

    function setUp() public {
        evidence = new EvidenceRegistryV3(owner);
        vm.prank(owner);
        evidence.setAttester(attester, true);
    }

    function test_attesterNonceIsIsolatedAndObservationWindowIsValidated() external {
        EvidenceRegistryV3.Attestation memory a = EvidenceRegistryV3.Attestation({
            attester: attester,
            attesterAuthority: keccak256("authority"),
            subject: keccak256("subject"),
            bondOrMandate: keccak256("bond"),
            evidenceSchema: keccak256("schema"),
            evidenceCommitment: keccak256("commitment"),
            observationStart: uint64(block.timestamp),
            observationEnd: uint64(block.timestamp),
            timestamp: uint64(block.timestamp),
            expiresAt: uint64(block.timestamp + 1 days),
            nonce: 7,
            independenceClass: 2,
            round: 1
        });
        bytes memory sig = _sign(a);
        evidence.register(a, sig);
        assertTrue(evidence.nonceUsed(attester, 7));

        a.round = 2;
        a.evidenceCommitment = keccak256("different");
        bytes memory reusedNonceSig = _sign(a);
        vm.expectRevert(EvidenceRegistryV3.NonceUsed.selector);
        evidence.register(a, reusedNonceSig);

        a.nonce = 8;
        a.observationEnd = a.observationStart - 1;
        vm.expectRevert(EvidenceRegistryV3.BadAttestation.selector);
        evidence.register(a, hex"");

        a.observationEnd = uint64(block.timestamp + 1);
        a.timestamp = a.observationEnd;
        vm.expectRevert(EvidenceRegistryV3.BadAttestation.selector);
        evidence.register(a, hex"");
    }

    function _sign(EvidenceRegistryV3.Attestation memory a) private returns (bytes memory) {
        bytes32 digest =
            keccak256(abi.encodePacked("\x19\x01", evidence.DOMAIN_SEPARATOR(), evidence.hashAttestation(a)));
        (uint8 v, bytes32 r, bytes32 s) = vm.sign(ATTESTER_KEY, digest);
        return abi.encodePacked(r, s, v);
    }
}
