contract NugBuds is ERC721, ERC721Enumerable, ERC721URIStorage, Pausable, Ownable, ERC721Burnable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;
    uint256 public maxSupply = 4200;
    uint256 public price = 42000000000000000;
    bool public saleOpen = false;
    bool public presaleOpen = false;
    string public baseURI;

    address princeWallet = 0x005b48aAF56bD031a208C87BF32bD55F7c11Aa36;
    address shWallet = 0x005b48aAF56bD031a208C87BF32bD55F7c11Aa36;
    address devWallet = 0x005b48aAF56bD031a208C87BF32bD55F7c11Aa36;
    address rkWallet = 0x005b48aAF56bD031a208C87BF32bD55F7c11Aa36;

    mapping(address => uint256) public Whitelist;

    receive() external payable {}

    constructor() ERC721('Nug Buds', 'NBC') {}

    function reserveMints(address to) public onlyOwner {
        for (uint256 i = 0; i < 35; i++) internalMint(to);
    }

    function whitelistAddress(address[] memory who, uint256 amount) public onlyOwner {
        for (uint256 i = 0; i < who.length; i++) Whitelist[who[i]] = amount;
    }

    function withdraw() public onlyOwner {
        uint256 balance = address(this).balance;
        payable(princeWallet).transfer((balance * 710) / 1000);
        payable(shWallet).transfer((balance * 50) / 1000);
        payable(devWallet).transfer((balance * 40) / 1000);
        payable(rkWallet).transfer((balance * 200) / 1000);
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function toggleSale() public onlyOwner {
        saleOpen = !saleOpen;
    }

    function togglePresale() public onlyOwner {
        presaleOpen = !presaleOpen;
    }

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

    function setPrice(uint256 newPrice) public onlyOwner {
        price = newPrice;
    }

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

    function internalMint(address to) internal {
        require(totalSupply() < maxSupply, 'supply depleted');
        _safeMint(to, _tokenIdCounter.current());
        _tokenIdCounter.increment();
    }

    function safeMint(address to) public onlyOwner {
        internalMint(to);
    }

    function mint(uint256 amount) public payable {
        require(msg.value >= price * amount, 'not enough was paid');

        if (!saleOpen) {
            require(presaleOpen == true, 'presale is not open');
            uint256 who = Whitelist[msg.sender];
            require(who > 0, 'this address is not whitelisted for the presale');
            require(amount <= who, 'this address is not allowed to mint that many during the presale');
            for (uint256 i = 0; i < amount; i++) internalMint(msg.sender);
            Whitelist[msg.sender] = who - amount;
            return;
        }

        require(amount <= 20, 'only 20 per transaction allowed');
        for (uint256 i = 0; i < amount; i++) internalMint(msg.sender);
    }

    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override(ERC721, ERC721Enumerable) whenNotPaused {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    // The following functions are overrides required by Solidity.

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory) {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC721Enumerable) returns (bool) {
        return super.supportsInterface(interfaceId);
    }
}
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
    super._burn(tokenId);
}

// The following functions are overrides required by Solidity.