contract Mintify is ERC721, Ownable {

    bool is_paused = false;
    uint16 max_per_user = 50;
    uint16 nextTokenId = 1;
    uint16 max_supply = 2222;
    uint256 mintPrice = 0;
    bool public IS_PRESALE_ACTIVE = true;
    string private baseURI = "https://ipfs.io/ipfs/QmUqSSZYxYG7YW6tUBQgbr4oXqTa4aeRD38h7W7vdUNoWK";
    mapping(address => bool) public whitelisted;


    // Constructor
    constructor() ERC721("Mintify", "MNTFY") {
            
    }

    // Mint
    function mint(address to, uint16 numberTokens) public payable {

        if ( msg.sender != owner() ) {
            require(msg.value + 1 > (mintPrice * numberTokens), "Not enough WEI sent");
            if (IS_PRESALE_ACTIVE) {
                require(whitelisted[to], "Address not whitelisted");
            }
            require((balanceOf(to) + numberTokens - 1) < max_per_user, "You've reached your mint limit");
        }
        require(!is_paused, "Minting is paused. Check back later.");
        require((numberTokens + nextTokenId - 2) < max_supply, "Your request will exceed max supply. Please try a smaller number");
        for (uint i=0; i < numberTokens; i++) {
            _safeMint(to, nextTokenId);
            nextTokenId++;
        }
       
    }

    // Sets BaseURI
    function setBaseURI(string calldata _baseURI ) public onlyOwner {
        baseURI = _baseURI;
    }

    // Gets total supply
    function totalSupply() public view returns(uint) {
        return nextTokenId - 1;
    }

    // Withdraw Balance to Address
    function withdraw(address payable _to) public onlyOwner {
        _to.transfer(address(this).balance);
    }

    // Sets mint price
    function setMintPrice(uint256 _mintprice) public onlyOwner {
        mintPrice = _mintprice;
    }

    // Sets max supply
    function setMaxSupply(uint16 _max_supply) public onlyOwner {
        max_supply = _max_supply;
    }

    // Sets max per user
    function setMaxPerUser(uint16 _max_per_user) public onlyOwner {
        max_per_user = _max_per_user;
    }

    // Sets paused state
    function setPaused(bool _is_paused) public onlyOwner {
        is_paused = _is_paused;
    }

    // Sets presale state
    function setPresale(bool _is_presale) public onlyOwner {
        IS_PRESALE_ACTIVE = _is_presale;
    }

    // Gets token URI
    function tokenURI(uint256 tokenId) public view virtual override(ERC721) returns (string memory) {
        require(_exists(tokenId), "Nonexistent token");
        return bytes(baseURI).length > 0 ? baseURI : "";
    }

    // Whitelist address
    function whitelistUser(address _user) external onlyOwner {
        whitelisted[_user] = true;
    }
    // Remove from whitelist
    function removeWhitelistUser(address _user) external onlyOwner {
        whitelisted[_user] = false;
    }
    // Bulk whitelist addresses
    function bulkWhitelist(address[] memory addresses) public onlyOwner {
        for (uint256 i = 0; i < addresses.length; i++) {
            if (whitelisted[addresses[i]] != true && addresses[i] != address(0)) {
                whitelisted[addresses[i]] = true;
            }
        }
    }

}
function removeWhitelistUser(address _user) external onlyOwner {
    whitelisted[_user] = false;
}

// Remove from whitelist