contract JenkinsTheValet is Ownable, ERC721 {

    event Mint(uint indexed _tokenId);

    uint public maxSupply = 6942; // Maximum tokens that can be minted
    uint public limitPerAccount = 69; // Maximum mints per wallet
    uint public mintFee = 0.069420 ether; // Price per mint
    uint public totalSupply = 0; // This is our mint counter as well
    mapping(uint => string) public tokenURIs; // Metadata location, updatable by owner
    mapping(address => uint) public mintCounts; // Amount minted per user
    string public _baseTokenURI; // Same for all tokens
    mapping(address => bool) public canWithdraw;
    bool public paused = true;

    constructor() payable ERC721("Jenkins the Valet", "JENKINS") {
    }

    function mint(address to, uint quantity) external payable {
        require(totalSupply + quantity <= maxSupply, "maxSupply of mints already reached");
        if(msg.sender != owner()) {
            require(!paused, "Paused");
            require(mintCounts[to] + quantity <= limitPerAccount, "max 69 mints per account");
            require(quantity * mintFee == msg.value, "Pay 0.69420 eth per mint");
        }
        mintCounts[to] += quantity;
        for (uint i = 0; i < quantity; i++) {
            totalSupply += 1; // 1-indexed instead of 0
            _mint(to, totalSupply);
            emit Mint(totalSupply);
        }
    }

    /**
     * @dev Returns a URI for a given token ID's metadata
     */
    function tokenURI(uint256 _tokenId) public view override returns (string memory) {
        return string(abi.encodePacked(_baseTokenURI, Strings.toString(_tokenId)));
    }

    // ADMIN FUNCTIONALITY

    /**
     * @dev Withdraw ETH
     */
    function withdraw() public {
        require(msg.sender == owner() || canWithdraw[msg.sender], "Nice try!");
        uint amount = address(this).balance;
        (bool success,) = msg.sender.call{value: amount}("");
        require(success, "Failed to send ether");
    }

    /**
     * @dev Pauses or unpauses the contract
     */
    function setPaused(bool _paused) public onlyOwner {
        paused = _paused;
    }

    /**
     * @dev Adds an address to the withdraw whitelist
     */
    function setWhitelist(address addr, bool val) public onlyOwner {
        canWithdraw[addr] = val;
    }

    /**
     * @dev Updates the base token URI for the metadata
     */
    function setBaseTokenURI(string memory __baseTokenURI) public onlyOwner {
        _baseTokenURI = __baseTokenURI;
    }
}
function setPaused(bool _paused) public onlyOwner {
    paused = _paused;
}

/**
 * @dev Pauses or unpauses the contract
 */