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

import {Test} from "forge-std/Test.sol";
import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
import {Chain138MainnetCheckpoint} from "../../contracts/mainnet-checkpoint/Chain138MainnetCheckpoint.sol";
import {BlockHeaderOracleExtension} from "../../contracts/mainnet-checkpoint/extensions/BlockHeaderOracleExtension.sol";
import {ExtensionIds} from "../../contracts/mainnet-checkpoint/libraries/ExtensionIds.sol";
import {CheckpointStorage} from "../../contracts/mainnet-checkpoint/storage/CheckpointStorage.sol";
import {CheckpointLeaf} from "../../contracts/mainnet-checkpoint/libraries/CheckpointLeaf.sol";
import {CheckpointFlags} from "../../contracts/mainnet-checkpoint/libraries/CheckpointFlags.sol";
import {CheckpointHubConfig} from "../../contracts/mainnet-checkpoint/libraries/CheckpointHubConfig.sol";

contract BlockHeaderOracleTest is Test {
    Chain138MainnetCheckpoint hub;
    BlockHeaderOracleExtension oracle;
    address admin = address(0xA11CE);
    address submitter = address(0xB0B);

    function setUp() public {
        Chain138MainnetCheckpoint impl = new Chain138MainnetCheckpoint();
        bytes memory initData = abi.encodeCall(
            Chain138MainnetCheckpoint.initialize,
            (admin, address(1), uint64(1), address(0))
        );
        hub = Chain138MainnetCheckpoint(address(new ERC1967Proxy(address(impl), initData)));
        oracle = new BlockHeaderOracleExtension(admin);
        vm.startPrank(admin);
        hub.grantRole(hub.SUBMITTER_ROLE(), submitter);
        CheckpointHubConfig.HubConfig memory cfg = CheckpointHubConfig.mainnetDefaults();
        cfg.enforcePreviousBatchId = false;
        cfg.requireValidatorSigs = false;
        cfg.allowCCIPIngress = false;
        hub.applyConfig(cfg);
        hub.registerExtension(
            ExtensionIds.BLOCK_ORACLE,
            address(oracle),
            oracle.HOOK_BEFORE_SUBMIT()
        );
        oracle.setRequireOracleRecord(true);
        vm.stopPrank();
    }

    function testRevertsWithoutOracleRecord() public {
        bytes32 bh = keccak256("bh");
        bytes32 sr = keccak256("sr");
        bytes32 root = _root();
        CheckpointStorage.CheckpointHeader memory header = _header(1, bh, sr, root);
        vm.prank(submitter);
        vm.expectRevert("oracle missing");
        hub.submitCheckpoint(header, hex"01", new bytes32[](0), "");
    }

    function testSubmitAfterOracleSet() public {
        bytes32 bh = keccak256("bh");
        bytes32 sr = keccak256("sr");
        vm.prank(admin);
        oracle.setBlockHeader(100, bh, sr);
        bytes32 root = _root();
        CheckpointStorage.CheckpointHeader memory header = _header(1, bh, sr, root);
        vm.prank(submitter);
        hub.submitCheckpoint(header, hex"01", new bytes32[](0), "");
        assertEq(hub.getLatestBatchId(), 1);
    }

    function _root() internal pure returns (bytes32) {
        CheckpointLeaf.PaymentLeafV1 memory leaf = CheckpointLeaf.PaymentLeafV1({
            txHash: keccak256("tx"),
            from: address(1),
            to: address(2),
            value: 1,
            blockNumber: 100,
            blockTimestamp: 1,
            gasUsed: 1,
            success: true
        });
        return CheckpointLeaf.paymentLeafV1(138, leaf);
    }

    function _header(uint64 batchId, bytes32 bh, bytes32 sr, bytes32 paymentsRoot)
        internal
        pure
        returns (CheckpointStorage.CheckpointHeader memory)
    {
        return CheckpointStorage.CheckpointHeader({
            batchId: batchId,
            previousBatchId: 0,
            chainId: 138,
            checkpointBlock: 100,
            startBlock: 99,
            endBlock: 100,
            blockHash: bh,
            stateRoot: sr,
            paymentsRoot: paymentsRoot,
            receiptsRoot: bytes32(0),
            txCount: 1,
            flags: CheckpointFlags.PARTIAL_BATCH,
            submittedAt: 0,
            submitter: address(0),
            contentURI: bytes32(0)
        });
    }
}
