contract PotatoPower is ERC721Enumerable, Ownable,Pausable {
    using Counters for Counters.Counter;
    
       struct SpecificAddresses{
        
        
        address userAddress;
        bool mint;
        
        
    }
    
    mapping(address => SpecificAddresses) public _whiteList;
    mapping(address=>bool) public _addressExist;
    mapping(uint256 => string) private _tokenURIs;
    
    Counters.Counter private _tokenIds;

    uint256 public maxSupply = 7777;
    uint256 public currentPrice = 0.05 ether;
    uint256 public maxQuantity=30;
    string  public tokenBaseURI;
    event MAX_SUPPLY_UPDATED(uint256 maxSupply);
    event MAX_PRICE_UPDATED(uint256 maxPrice);

    constructor(string memory _baseURII) ERC721("Potato Power", "PW"){tokenBaseURI=_baseURII;}
        function getPrice(uint256 _quantity) public view returns (uint256) {
       
           return _quantity*currentPrice ;
        }
        

    function mint( uint256 _quantity) whenNotPaused() public payable returns (uint256) {
    require(totalSupplyy()+_quantity<=maxSupply,"Quantity must be lesser then MaxSupply");
    require(_quantity>0,"quantity must be greater then zero");
    require(_quantity <= maxQuantity, "Your are not allowed to mint more than 30 tokens");
    require(getPrice(_quantity) == msg.value, "Ether value sent is not correct");

        uint256 newItemId;

        for (uint256 i = 0; i < _quantity; i++) {
       
        _tokenIds.increment();
         newItemId = _tokenIds.current();
        _mint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenBaseURI);
    }
            return newItemId;

    }
       function mintByAdmin( uint256 _quantity)  public  onlyOwner  returns (uint256) {
        require(_quantity <= 60, "Your are not allowed to mint more than 60 tokens");
        require(totalSupplyy()+_quantity<=maxSupply,"Quantity must be lesser then MaxSupply");
        require(_quantity>0,"quantity must be greater then zero");
        uint256 newItemId;

        for (uint256 i = 0; i < _quantity; i++) {
       
        _tokenIds.increment();
         newItemId = _tokenIds.current();
        _mint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenBaseURI);
    }
            return newItemId;

    }

     /**
     * @dev See {IERC721Enumerable-totalSupply}.
     */
    function totalSupplyy() private view returns (uint256) {
        return _tokenIds.current();
    }

     /**
     * @dev Withdraw ether from this contract (Callable by owner)
     */
    function withdraw() public onlyOwner {
        uint amount = address(this).balance;
        payable(owner()).transfer(amount);
    }
    
    function addWhiteList(address whiteAddress)public onlyOwner {
        require(!_addressExist[whiteAddress],"Address already Exist");
        
        _whiteList[whiteAddress]=SpecificAddresses({
            userAddress :msg.sender,
            mint:false
           });
           
           _addressExist[whiteAddress]=true;
        
    }
    
    function mintBeta() public payable{
        
        require(_addressExist[msg.sender]==true,"Address not Found in whitelist");
        SpecificAddresses storage myaddress = _whiteList[msg.sender];
        
        require(myaddress.mint==false,"User Already minted a token");
        require(msg.value==currentPrice,"Price Error");
        require(_tokenIds.current() < maxSupply, "Max Supply Exceeded");

        uint256 newItemId;
         _tokenIds.increment();
         newItemId = _tokenIds.current();
        _mint(msg.sender, newItemId);
        _setTokenURI(newItemId, tokenBaseURI);
        myaddress.mint=true;
        
    }
    
     function burn(uint256 tokenId) public  {
         require(ownerOf(tokenId)==msg.sender,"you are not owner of this id");
        _burn(tokenId);
    }
    
     function tokensOfOwner(address _owner) public view returns (uint256[] memory)
    {
        uint256 count = balanceOf(_owner);
        uint256[] memory result = new uint256[](count);
        for (uint256 index = 0; index < count; index++) {
            result[index] = tokenOfOwnerByIndex(_owner, index);
        }
        return result;
    }
    
 
    function _setTokenURI(uint256 tokenId, string memory tokenURI) internal virtual {
        require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
        _tokenURIs[tokenId] = tokenURI;
    }


    function updateCurrentPrice(uint256 _price) public onlyOwner {
        currentPrice = _price;
        emit MAX_PRICE_UPDATED(_price);
    }
        
  
    
 function _baseURI() internal view override returns (string memory) {
    return tokenBaseURI ;
  }
  
  function updateBaseURI(string memory _baseURIII) public onlyOwner returns(string memory )
  {
      tokenBaseURI=_baseURIII;
      return tokenBaseURI;
  }
   function pause() public onlyOwner whenNotPaused 
   {
        _pause();
    }
    
     function unpause() public onlyOwner whenPaused 
     {
        _unpause();
    }
    
    
}
function totalSupplyy() private view returns (uint256) {
    return _tokenIds.current();
}

/**
 * @dev See {IERC721Enumerable-totalSupply}.
 */