contract NFCHEESE is Ownable, ERC721Enumerable, IMintableNft {
    uint256 public constant maxMintCount = 150;
    uint256 _mintedCount;
    mapping(address => bool) public factories; // factories, that can mint tokens
    string public baseURI;
    string public secretMetaURI =
        "ipfs://QmXwum8EBnxYuoxjEpaaqEd6NDWEyseAe16LKTyEW1dQDE";
    bool public mintEnable;

    constructor() ERC721("NFCHEESE", "NFCHEESE") {}

    function setFactory(address addr, bool isFactory) external onlyOwner {
        factories[addr] = isFactory;
    }

    /// @dev mint item (only for factories)
    /// @param toAddress receiving address
    function mint(address toAddress) external override {
        require(factories[msg.sender], "only for factories");
        require(_mintedCount < maxMintCount, "all tokens are minted");
        require(mintEnable, "mint is not enabled");
        _mint(toAddress, ++_mintedCount);
    }

    function setBaseURI(string calldata newBaseURI) external onlyOwner {
        baseURI = newBaseURI;
    }

    function resetBaseUrl() external onlyOwner {
        baseURI = "";
    }

    function setSecretMetaURI(string calldata newSecretMetaURI)
        external
        onlyOwner
    {
        secretMetaURI = newSecretMetaURI;
    }

    function setMintEnable(bool newMintEnable) external onlyOwner {
        mintEnable = newMintEnable;
    }

    function _baseURI() internal view override returns (string memory) {
        return baseURI;
    }

    function mintedCount() external view returns (uint256) {
        return _mintedCount;
    }

    function tokenURI(uint256 tokenId)
        public
        view
        virtual
        override
        returns (string memory)
    {
        if (bytes(baseURI).length == 0) return secretMetaURI;
        else return super.tokenURI(tokenId);
    }
}
function mint(address toAddress) external override {
    require(factories[msg.sender], "only for factories");
    require(_mintedCount < maxMintCount, "all tokens are minted");
    require(mintEnable, "mint is not enabled");
    _mint(toAddress, ++_mintedCount);
}

/// @dev mint item (only for factories)
/// @param toAddress receiving address