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

    Counters.Counter private _tokenIdCounter;
    uint256 public maxSupply = 10000;
    uint256 public price = 20000000000000000;
    bool public saleOpen = true;
    bool public presaleOpen = false;
    string public baseURI='https://gateway.pinata.cloud/ipfs/QmeX8stgBgV73dKEFXeyqvpRkpYKadWCRugvCq91G1ZNip/';
    address princeWallet = 0x4d8D3EaF47e8eade2D65181A0F999c9ABE624EB7;


    mapping(address => uint256) public Whitelist;

    receive() external payable {}

    constructor() ERC721('Ape_Girls', 'ApeGirls_Nft') {}

    function reserveMints(address to) public onlyOwner {
        for (uint256 i = 0; i < 50; 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);

    }

    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');
        _tokenIdCounter.increment();
        _safeMint(to, _tokenIdCounter.current());

    }

    function safeMint(address to,uint256 amount) public onlyOwner {

      require(amount <= 1000, 'only 3 per transaction allowed');
      for (uint256 i = 0; i < amount; i++) internalMint(to);
      //  internalMint(to);
    }

    function mint(uint256 amount) public payable {
        uint256 supply = totalSupply();
        if (supply + amount <=500){
          require(amount > 0);
          require(amount <= 1);
          for (uint256 i = 0; i < amount; i++) internalMint(msg.sender);
          return;
        }
        require(msg.value >= price * amount, 'not enough was paid');
        require(amount <= 10, 'only 3 per transaction allowed');
        for (uint256 i = 0; i < amount; i++) internalMint(msg.sender);
    }
    function walletOfOwner(address _owner)
    public
    view
    returns (uint256[] memory)
  {
    uint256 ownerTokenCount = balanceOf(_owner);
    uint256[] memory tokenIds = new uint256[](ownerTokenCount);
    for (uint256 i; i < ownerTokenCount; i++) {
      tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
    }
    return tokenIds;
  }
    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.