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

import "./interfaces/IGatekeeper.sol";

contract Gatekeeper is IGatekeeper {
    uint256 public override ghostedSupply;
    address public immutable staking;

    uint256 private _aggregatedPublicKey;
    mapping(uint256 => mapping(uint256 => bool)) private _executedTransaction;

    constructor(
        address _staking,
        uint256 _ghostedSupply
    ) {
        ghostedSupply = _ghostedSupply;
        staking = _staking;
    }

    function ghost(bytes32 receiver, uint256 amount) external override {
        if (msg.sender != staking) revert NotStaking();
        ghostedSupply += amount;
        emit Ghosted(receiver, amount);
    }

    function materialize(
        address receiver,
        uint256 amount,
        uint256 rx,
        uint256 s
    ) external override {
        if (msg.sender != staking) revert NotStaking();
        _checkTransactionExistence(rx, s);
        bytes32 message = keccak256(abi.encodePacked("materialize", receiver, amount));

        if (_incorrectSignature(rx, s, message)) revert WrongSignature();
        ghostedSupply -= amount;
        emit Materialized(receiver, amount);
    }

    function rotate(
        uint256 aggregatedPublicKey,
        uint256 rx,
        uint256 s
    ) external override {
        _checkTransactionExistence(rx, s);
        bytes32 message = keccak256(abi.encodePacked("rotate", aggregatedPublicKey));

        if (_incorrectSignature(rx, s, message)) revert WrongSignature();
        _aggregatedPublicKey = aggregatedPublicKey;
        emit Rotated(aggregatedPublicKey);
    }

    function _checkTransactionExistence(uint256 rx, uint256 s) private {
        if (_executedTransaction[rx][s]) revert AlreadyExecuted();
        _executedTransaction[rx][s] = true;
    }

    function _incorrectSignature(uint256 rx, uint256 s, bytes32 m) private pure returns (bool) {
        // no logic below, just to suppress warnings from solc
        uint256 void = rx;
        void = s;
        void = uint256(m);

        // always bad signature for now
        return true;
    }
}
