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

/**
 * @title MirrorManager
 * @notice Registry of mirrored token/contract addresses across chains with replay protection and pausability
 */
contract MirrorManager {
    address public admin;
    bool public paused;

    // mapping: (sourceChain, sourceAddress) => (destChain => destAddress)
    mapping(uint64 => mapping(address => mapping(uint64 => address))) public mirrors;
    mapping(bytes32 => bool) public processed; // optional replay protection for off-chain message ids

    event AdminChanged(address indexed newAdmin);
    event Paused();
    event Unpaused();
    event MirrorSet(uint64 indexed srcChain, address indexed src, uint64 indexed dstChain, address dst);
    event MirrorRemoved(uint64 indexed srcChain, address indexed src, uint64 indexed dstChain);
    event Processed(bytes32 indexed id);

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

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

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

    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();
    }

    function setMirror(uint64 srcChain, address src, uint64 dstChain, address dst) external onlyAdmin whenNotPaused {
        require(src != address(0) && dst != address(0), "zero addr");
        mirrors[srcChain][src][dstChain] = dst;
        emit MirrorSet(srcChain, src, dstChain, dst);
    }

    function removeMirror(uint64 srcChain, address src, uint64 dstChain) external onlyAdmin whenNotPaused {
        delete mirrors[srcChain][src][dstChain];
        emit MirrorRemoved(srcChain, src, dstChain);
    }

    function getMirror(uint64 srcChain, address src, uint64 dstChain) external view returns (address) {
        return mirrors[srcChain][src][dstChain];
    }

    function markProcessed(bytes32 id) external onlyAdmin {
        processed[id] = true;
        emit Processed(id);
    }
}


