contract EaselyRegistry is AccessControlEnumerable, IEaselyRegistry {

    // Creator struct which holds all the required info
    struct Creator {
        bool paused;
        address creatorAddress;
        uint256 easelyFeeBPS;
    }

    bytes32 public constant CREATOR_ROLE = keccak256("CREATOR_ROLE");

    uint256 public DEFAULT_FEE_BPS = 500;
    uint256 public MAX_EASELY_FEE_BPS = 500;
    uint256 private BASIS_POINT_CONVERSION = 10_000;

    mapping(address => Creator) private _addressToCreator;

    constructor() {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
        _setupRole(CREATOR_ROLE, _msgSender());
    }

    /**
     * @dev Creator address is set on registration so unregistered creators have address(0)
     */
    function _isCreatorRegistered(address creatorAddress) internal view returns (bool) {
        return _addressToCreator[creatorAddress].creatorAddress == creatorAddress && creatorAddress != address(0);
    }

    /**
     * @dev Internal helper function to see if sender can pause an address
     */
    function _canPause(address creatorAddress) internal view returns (bool) {
        return hasRole(CREATOR_ROLE, _msgSender()) || _msgSender() == creatorAddress;
    }

    /**
     * @dev Takes in a creatorAddress and fee in BPS. This changes calculateCreatorPayout.
     *
     * Requirements:
     * - sender must have `CREATOR_ROLE`
     * - fee cannot be over MAX_EASELY_FEE_BPS
     */
    function registerCreator(address creatorAddress, uint256 easelyFeeBPS) external {
        require(hasRole(CREATOR_ROLE, _msgSender()), "Need creator role");
        require(!_isCreatorRegistered(creatorAddress), "Creator already exists");
        require(easelyFeeBPS <= MAX_EASELY_FEE_BPS, "Max fee is 5% (500 BPS)");

        Creator memory newCreator;
        newCreator.creatorAddress = creatorAddress;
        newCreator.easelyFeeBPS = easelyFeeBPS;
        newCreator.paused = false;

        _addressToCreator[creatorAddress] = newCreator;
        
        emit CreatorRegistered(creatorAddress);
    }

    /**
     * @dev Updates the default BPS for all creators not on the registry.
     *
     * Requirements:
     * - sender has `DEFAULT_ADMIN_ROLE`.
     * - fee cannot be over MAX_EASELY_FEE_BPS
     */
    function updateDefaultBPSFee(uint256 bpsFee) external {
        require(hasRole(DEFAULT_ADMIN_ROLE, _msgSender()), "Need creator role");
        require(bpsFee <= MAX_EASELY_FEE_BPS, "Max fee is 5% (500 BPS)");

        DEFAULT_FEE_BPS = bpsFee;
    }

    function updateBPSFee(address creatorAddress, uint256 easelyFeeBPS) external {
        require(hasRole(CREATOR_ROLE, _msgSender()), "Need creator role");
        require(easelyFeeBPS <= MAX_EASELY_FEE_BPS, "Max fee is 5% (500 BPS)");
        require(_isCreatorRegistered(creatorAddress), "CreatorAddress is not registered");

        _addressToCreator[creatorAddress].easelyFeeBPS = easelyFeeBPS;
    }

    /**
     * @dev Pauses our creator which prevents calculateCreatorPayout and any transfers for 
     * marketplace contracts that read from this registry.
     *
     * Requirements:
     * - Creator cannot be already paused
     */
    function pauseCreator(address creatorAddress) external {
        require(_isCreatorRegistered(creatorAddress), "CreatorAddress is not registered");
        require(_canPause(creatorAddress), "Sender cannot pause this creator");
        require(!_addressToCreator[creatorAddress].paused, "Creator already paused");
        _addressToCreator[creatorAddress].paused = true;

        emit CreatorPaused(creatorAddress);
    }

    /**
     * @dev Unpauses our creator which enables calculateCreatorPayout and any marketplaces
     * that read from this registry.
     *
     * Requirements:
     * - Creator must be paused
     */
    function unpauseCreator(address creatorAddress) external {
        require(_isCreatorRegistered(creatorAddress), "CreatorAddress is not registered");
        require(_canPause(creatorAddress), "Sender cannot unpause this creator");
        require(_addressToCreator[creatorAddress].paused, "Creator not paused");
        _addressToCreator[creatorAddress].paused = false;

        emit CreatorUnpaused(creatorAddress);
    }

    /**
     * @dev See {IEaselyRegistry-calculateCreatorPayout}.
     */
    function calculateCreatorPayout(address creatorAddress, uint256 payinValue) 
        external view override returns (uint256) 
    {
        require(!_addressToCreator[creatorAddress].paused, "Creator is paused");
        uint256 easelyFeeBPS;

        if (!_isCreatorRegistered(creatorAddress)) {
            easelyFeeBPS = DEFAULT_FEE_BPS;
        } else {
            easelyFeeBPS = _addressToCreator[creatorAddress].easelyFeeBPS;
        }

        uint256 ownerCut = BASIS_POINT_CONVERSION - easelyFeeBPS;

        // Divide first to prevent overflow. 
        // Unflow is prevented by marketplace's minimum value
        uint256 creatorPayout = payinValue / BASIS_POINT_CONVERSION * ownerCut;

        // This should never fail
        require(creatorPayout <= payinValue, "Cannot payout more than payin");

        return creatorPayout;
    }

    /**
     * @dev See {IEaselyRegistry-isCreatorRegistered}.
     */
    function isCreatorRegistered(address creatorAddress) external view override returns (bool) {
        return _isCreatorRegistered(creatorAddress);
    }

    /**
     * @dev See {IEaselyRegistry-isCreatorPaused}.
     */
    function isCreatorPaused(address creatorAddress) external view override returns (bool) {
        return _addressToCreator[creatorAddress].paused;
    }
}
function _canPause(address creatorAddress) internal view returns (bool) {
        return hasRole(CREATOR_ROLE, _msgSender()) || _msgSender() == creatorAddress;
    }
/**
 * @dev Internal helper function to see if sender can pause an address
 */