contract VelorexMembersClub is ERC721A, Ownable {

    using Address for address;
    using MerkleProof for bytes32[];
    using SafeMath for uint256;
    using Strings for uint;

    string public baseURI;
    string public baseExtension = ".json";
    uint256 public cost = 0.1133 ether;
    uint256 public whitelistCost = 0.084975 ether;
    uint256 public maxSupply = 2500;
    uint256 public maxMintPerWallet = 5;
    uint256 public dropLimit = 500;
    bool public paused = true;
    
    mapping(address => bool) public adminRights;
    mapping(address => bool) public whitelistWallets;

    WhitelistData[] public whitelistData;
    
      struct WhitelistData {
        uint256 maxMintPerWallet;
        uint256 price;
        bytes32 merkleroot;
}

constructor(
        string memory _name,
        string memory _symbol,
        string memory _initBaseURI
    ) ERC721A(_name, _symbol) {
        setBaseURI(_initBaseURI);
        _safeMint(msg.sender, 15);
}

modifier whenAddressOnWhitelist(bytes32[] memory _merkleproof) {
        require(MerkleProof.verify(
            _merkleproof,
            getPresale().merkleroot,
            keccak256(abi.encodePacked(msg.sender))
            ),
            "Not on whitelist"
        );
        _;
}
 
    // internal functions
function _baseURI() internal view virtual override returns (string memory) {
        return baseURI;
}

function mint(uint256 _amountToMint) external payable {

     uint256 supply = totalSupply();
        require(_amountToMint > 0, "Well, what's the point in minting nothing? ;) Please try again.");
        require(supply + _amountToMint <= maxSupply, "Maximum supply reached! You'll have to buy from the secondary market!");
        require(supply + _amountToMint <= dropLimit, "Sorry, you'll have to wait untill the next drop is released! Join the telegram to find out - t.me/velorex_net");

    if (msg.sender != owner()){
	    require(_amountToMint <= maxMintPerWallet, "You can only mint 5 per transaction");
	    require(!paused, "Minting is currently paused");
        require((_numberMinted(msg.sender) + _amountToMint) <= maxMintPerWallet, "You can't mint that many NFTs with this wallet! Check the limit please.");

    if (adminRights[msg.sender] != true) {
    if (whitelistWallets[msg.sender] != true) {
        //full price
        require(msg.value >= cost * _amountToMint, "Incorrect amount entered, try increasing the value."); 
    }   else {
        //apply discount
        require(msg.value >= whitelistCost * _amountToMint, "Incorrect amount entered, try increasing the value.");
        }
    }
    }
        _safeMint(msg.sender, _amountToMint);
        payable(owner()).transfer(msg.value);
}

function tokenURI(uint tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        string memory currentBaseURI = _baseURI();
        return
            bytes(currentBaseURI).length > 0
                ? string(
                    abi.encodePacked(
                        currentBaseURI,
                        tokenId.toString(),
                        baseExtension
                    )
                )
                : "";
}

function getPresale() private view returns (WhitelistData storage) {
        return whitelistData[0];
}

function setCost(uint256 _newCost) public onlyOwner {
        cost = _newCost;
}

function setDiscountedCost(uint256 _newCost) public onlyOwner {
        whitelistCost = _newCost;
}

function setmaxMintPerWallet(uint256 _newmaxMintPerWallet) public onlyOwner {
        maxMintPerWallet = _newmaxMintPerWallet;
}

function setDropLimit(uint256 _newDropLimit) public onlyOwner {
        dropLimit = _newDropLimit;
}

function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseURI = _newBaseURI;
}

function setBaseExtension(string memory _newBaseExtension) public onlyOwner {
        baseExtension = _newBaseExtension;
}

function pauseMinting(bool _state) public onlyOwner {
        paused = _state;
}

function giveAdminRights(address _user) public  onlyOwner {
        adminRights[_user] = true;
}

function removeAdminRights(address _user) public onlyOwner {
        adminRights[_user] = false;
}

function addToWhitelist(address[] memory _users) public onlyOwner {
        for (uint256 i = 0; i < 2; i++) {
            whitelistWallets[_users[i]] = true;
        }
}

function removeFromWhitelist(address _user) public onlyOwner {
        whitelistWallets[_user] = false;
}

function withdraw() public payable onlyOwner {
        (bool success, ) = payable(msg.sender).call{
            value: address(this).balance
        }("");
        require(success);
}

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

// internal functions