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

/**
 * @title MainnetTether
 * @notice Anchors Chain-138 state proofs to Ethereum Mainnet (Kaleido-style)
 * @dev Stores signed state proofs from Chain-138 validators, creating an immutable
 *      and verifiable record of Chain-138's state on Mainnet
 */
contract MainnetTether {
    address public admin;
    bool public paused;

    // Chain-138 chain ID
    uint64 public constant CHAIN_138 = 138;

    // State proof structure
    struct StateProof {
        uint256 blockNumber;           // Chain-138 block number
        bytes32 blockHash;              // Chain-138 block hash
        bytes32 stateRoot;              // Chain-138 state root
        bytes32 previousBlockHash;      // Previous block hash
        uint256 timestamp;              // Block timestamp
        bytes signatures;               // Collective signatures from validators
        uint256 validatorCount;         // Number of validators that signed
        bytes32 proofHash;               // Hash of the proof (for indexing)
    }

    // Mapping: blockNumber => StateProof
    mapping(uint256 => StateProof) public stateProofs;

    // Array of all anchored block numbers (for iteration)
    uint256[] public anchoredBlocks;

    // Mapping: proofHash => bool (replay protection)
    mapping(bytes32 => bool) public processed;

    // Events
    event AdminChanged(address indexed newAdmin);
    event Paused();
    event Unpaused();
    event StateProofAnchored(
        uint256 indexed blockNumber,
        bytes32 indexed blockHash,
        bytes32 indexed stateRoot,
        uint256 timestamp,
        uint256 validatorCount
    );

    modifier onlyAdmin() {
        require(msg.sender == admin, "only admin");
        _;
    }

    modifier whenNotPaused() {
        require(!paused, "paused");
        _;
    }

    constructor(address _admin) {
        require(_admin != address(0), "zero admin");
        admin = _admin;
    }

    /**
     * @notice Anchor a state proof from Chain-138
     * @param blockNumber Chain-138 block number
     * @param blockHash Chain-138 block hash
     * @param stateRoot Chain-138 state root
     * @param previousBlockHash Previous block hash
     * @param timestamp Block timestamp
     * @param signatures Collective signatures from validators
     * @param validatorCount Number of validators that signed
     */
    function anchorStateProof(
        uint256 blockNumber,
        bytes32 blockHash,
        bytes32 stateRoot,
        bytes32 previousBlockHash,
        uint256 timestamp,
        bytes calldata signatures,
        uint256 validatorCount
    ) external onlyAdmin whenNotPaused {
        require(blockNumber > 0, "invalid block");
        require(blockHash != bytes32(0), "invalid hash");
        require(stateRoot != bytes32(0), "invalid state root");
        require(validatorCount > 0, "no validators");
        require(signatures.length > 0, "no signatures");

        // Calculate proof hash for replay protection
        bytes32 proofHash = keccak256(
            abi.encodePacked(
                blockNumber,
                blockHash,
                stateRoot,
                previousBlockHash,
                timestamp,
                signatures
            )
        );

        require(!processed[proofHash], "already processed");
        require(stateProofs[blockNumber].blockNumber == 0, "block already anchored");

        // Store state proof
        stateProofs[blockNumber] = StateProof({
            blockNumber: blockNumber,
            blockHash: blockHash,
            stateRoot: stateRoot,
            previousBlockHash: previousBlockHash,
            timestamp: timestamp,
            signatures: signatures,
            validatorCount: validatorCount,
            proofHash: proofHash
        });

        anchoredBlocks.push(blockNumber);
        processed[proofHash] = true;

        emit StateProofAnchored(
            blockNumber,
            blockHash,
            stateRoot,
            timestamp,
            validatorCount
        );
    }

    /**
     * @notice Get state proof for a specific block
     * @param blockNumber Chain-138 block number
     * @return proof State proof structure
     */
    function getStateProof(uint256 blockNumber) external view returns (StateProof memory proof) {
        require(stateProofs[blockNumber].blockNumber != 0, "not anchored");
        return stateProofs[blockNumber];
    }

    /**
     * @notice Check if a block is anchored
     * @param blockNumber Chain-138 block number
     * @return true if anchored
     */
    function isAnchored(uint256 blockNumber) external view returns (bool) {
        return stateProofs[blockNumber].blockNumber != 0;
    }

    /**
     * @notice Get total number of anchored blocks
     * @return count Number of anchored blocks
     */
    function getAnchoredBlockCount() external view returns (uint256) {
        return anchoredBlocks.length;
    }

    /**
     * @notice Get anchored block number at index
     * @param index Index in anchoredBlocks array
     * @return blockNumber Block number
     */
    function getAnchoredBlock(uint256 index) external view returns (uint256) {
        require(index < anchoredBlocks.length, "out of bounds");
        return anchoredBlocks[index];
    }

    /**
     * @notice Admin functions
     */
    function setAdmin(address newAdmin) external onlyAdmin {
        require(newAdmin != address(0), "zero admin");
        admin = newAdmin;
        emit AdminChanged(newAdmin);
    }

    function pause() external onlyAdmin {
        paused = true;
        emit Paused();
    }

    function unpause() external onlyAdmin {
        paused = false;
        emit Unpaused();
    }
}

