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

import { PartnershipBondV3Safe } from "../../contracts/bonds/PartnershipBondV3Safe.sol";
import { V3Fixtures } from "../helpers/V3Fixtures.sol";

/// @notice Invariant #4 — Same terms cannot be replayed:
///   (a) with a different chainId       → BadChain
///   (b) with the same nonce twice      → NonceUsed
/// Fork/version replay is prevented by the EIP-712 domain separator rebinding
/// on `block.chainid` and by including protocolVersion inside `Terms`.
contract Inv04_NoSignatureReplay is V3Fixtures {
    PartnershipBondV3Safe internal bonds;

    function setUp() public {
        _setUpDependencies();
        bonds = new PartnershipBondV3Safe(
            owner, address(0), address(consensus), address(disputeRegistry), 10 ether, 20 ether, 100 ether, address(0)
        );
    }

    function _baseTerms(uint96 nonce, uint256 chainId) internal view returns (PartnershipBondV3Safe.Terms memory t) {
        t = PartnershipBondV3Safe.Terms({
            bondId: 1,
            partyA: partyA,
            partyB: partyB,
            partyAStake: 1 ether,
            partyBStake: 1 ether,
            stakeAsset: address(0),
            partnershipType: bytes32("test"),
            breachConditionsHash: bytes32(0),
            objectiveRuleClass: 0,
            objectiveRuleSchemaVersion: 0,
            flourishRewardConditionsHash: bytes32(0),
            rewardProgramId: 0,
            proposalDeadline: uint64(block.timestamp + 1 days),
            activePeriodStart: uint64(block.timestamp + 2 days),
            activePeriodEnd: uint64(block.timestamp + 30 days),
            challengeWindow: 3 days,
            nonce: nonce,
            chainId: chainId,
            protocolVersion: "3.0.0"
        });
    }

    function test_wrong_chainId_rejected() external {
        PartnershipBondV3Safe.Terms memory t = _baseTerms(1, block.chainid + 1);
        vm.expectRevert(PartnershipBondV3Safe.BadChain.selector);
        bonds.createBond(t, hex"", hex"");
    }

    function test_nonce_reuse_rejected_after_a_valid_first_submission() external {
        PartnershipBondV3Safe.Terms memory t = _baseTerms(7, block.chainid);
        bytes memory sigA = _signPartnership(bonds, t, PARTY_A_KEY);
        bytes memory sigB = _signPartnership(bonds, t, PARTY_B_KEY);

        uint256 firstBondId = bonds.createBond(t, sigA, sigB);
        assertEq(firstBondId, 1);

        vm.expectRevert(PartnershipBondV3Safe.NonceUsed.selector);
        bonds.createBond(t, sigA, sigB);
    }
}
