contract PartyPandas is ERC721, Ownable {
  using Address for address;
  using Counters for Counters.Counter;

  Counters.Counter private _tokenCount;

  string public baseURI = "https://api.partypandas.co/metadata/";
  uint256 public constant price = 40000000000000000; // 0.04 ETH
  uint256 public constant maxTokens = 10000;
  uint256 public maxWallet = 50;
  bool public saleIsActive = true;
  bool public hasReserved = false;

  mapping(address => uint256) public minted; // To check how many tokens an address has minted

  constructor() ERC721("Party Pandas ", "PARTYPANDAS") {}

  // reserve (100 tokens)
  function reserve() external onlyOwner {
    require(!hasReserved, "Tokens have already been reserved.");

    for (uint256 i; i < 100; i++) {
      _tokenCount.increment();
      _safeMint(msg.sender, _tokenCount.current());
    }
    hasReserved = true;
  }

  function mint(uint256 _amount) external payable {
    require(saleIsActive, "Sale must be active");
    require(
      minted[msg.sender] + _amount <= maxWallet,
      "Purchase would exceed max tokens per wallet"
    );
    require(
      _tokenCount.current() + _amount <= maxTokens,
      "Purchase would exceed max supply of tokens"
    );
    require(msg.value >= price * _amount, "Ether value sent is not correct");

    for (uint256 i; i < _amount; i++) {
      _tokenCount.increment();
      _safeMint(msg.sender, _tokenCount.current());
    }

    minted[msg.sender] += _amount;
  }

  function totalSupply() public view returns (uint256) {
    return _tokenCount.current();
  }

  function setBaseURI(string memory __baseURI) external onlyOwner {
    baseURI = __baseURI;
  }

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

  function flipSaleState() public onlyOwner {
    saleIsActive = !saleIsActive;
  }

  function setMaxWallet(uint256 _newMaxWallet) external onlyOwner {
    maxWallet = _newMaxWallet;
  }

  function withdrawAll() external onlyOwner {
    uint256 balance = address(this).balance;
    payable(msg.sender).transfer(balance);
  }
}
function reserve() external onlyOwner {
  require(!hasReserved, "Tokens have already been reserved.");

  for (uint256 i; i < 100; i++) {
    _tokenCount.increment();
    _safeMint(msg.sender, _tokenCount.current());
  }
  hasReserved = true;
}

// reserve (100 tokens)