contract EvilApeClub is Ownable, ERC721A, ReentrancyGuard {
    using Strings for uint256;


  uint256 public MAX_PER_Transtion = 10; // maximam amount that user can mint

    uint256 public  PRICE = 0.06 ether; 
    uint256 public WPRICE = 0.06 ether; 
    uint256 public SPRICE = 0.065 ether;

  uint256 private constant TotalCollectionSize_ = 6969; // total number of nfts
  uint256 private constant MaxMintPerBatch_ = 10; //max mint per traction


  bool public _revelNFT = false;
  string private _baseTokenURI;
  string private _uriBeforeRevel;
  uint public reserve = 250;



  uint public status = 0; //0-pause 2-whitelist 3-public

  mapping(address => bool) private whitelistedAddresses;


  constructor() ERC721A("Evil Ape Club","EAC", MaxMintPerBatch_, TotalCollectionSize_) {
    _uriBeforeRevel = "https://gateway.pinata.cloud/ipfs/Qmd8qmncBofLiuq5rwsVmERGFJKAJ1ct3u5DrJeGcgmX5t/revealMeta.json";
  }

  modifier callerIsUser() {
    require(tx.origin == msg.sender, "The caller is another contract");
    _;
  }
 
  function mint(uint256 quantity) external payable callerIsUser {
    require(status == 1 || status == 2 , "Sale is not Active");
    require(totalSupply() + quantity <= collectionSize-reserve-1, "reached max supply");
    require(quantity <= MAX_PER_Transtion,"can not mint this many");
    require(msg.value >= PRICE * quantity, "Need to send more ETH.");
    _safeMint(msg.sender, quantity);

    uint256 d = 3;
    if(status == 2) d = 5;

    if(d == 3){
        if(quantity >= 3 && quantity < 6){
        _safeMint(msg.sender, 1);

        } else if(quantity == 6){
        _safeMint(msg.sender, 2);
        }
    } else if(d == 5) {
        if(quantity >= 5 && quantity < 10){
        _safeMint(msg.sender, 1);

        } else if(quantity == 10){
        _safeMint(msg.sender, 2);
        }
    }

  }
//   string(abi.encodePacked(baseURI, tokenId.toString()))

   function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
    require(_exists(tokenId),"ERC721Metadata: URI query for nonexistent token");
    if(_revelNFT){
    string memory baseURI = _baseURI();
    uint256 tokenID = tokenId + 1;
    return
      bytes(baseURI).length > 0
        ? string(abi.encodePacked(baseURI, "/", tokenID.toString(), ".json")) : "";
        } else {
            return _uriBeforeRevel;
        }
  }

    function isWhitelisted(address _user) public view returns (bool) {
    return whitelistedAddresses[_user];
  }


  
  function addNewWhitelistUsers(address[] calldata _users) public onlyOwner {
    // ["","",""]
    for(uint i=0;i<_users.length;i++)
        whitelistedAddresses[_users[i]] = true;
  }

  function setURIbeforeRevel(string memory URI) external onlyOwner {
    _uriBeforeRevel = URI;
  }

  function setBaseURI(string memory baseURI) external onlyOwner {
    _baseTokenURI = baseURI;
  }
  function _baseURI() internal view virtual override returns (string memory) {
    return _baseTokenURI;
  }
  function numberMinted(address owner) public view returns (uint256) {
    return _numberMinted(owner);
  }
  function getOwnershipData(uint256 tokenId)
    external
    view
    returns (TokenOwnership memory)
  {
    return ownershipOf(tokenId);
  }

  function withdrawMoney() external onlyOwner nonReentrant {
    (bool success, ) = msg.sender.call{value: address(this).balance}("");
    require(success, "Transfer failed.");
  }

  function changeRevelStatus() external onlyOwner {
    _revelNFT = !_revelNFT;
  }

  function changeMintPrice(uint256 _newPrice) external onlyOwner
  {
      PRICE = _newPrice;
  }
  function changeMAX_PER_Transtion(uint256 q) external onlyOwner
  {
      MAX_PER_Transtion = q;
  }

  function setStatus(uint256 s)external onlyOwner{
      status = s;
      if(s==1){
            PRICE = WPRICE;
            MAX_PER_Transtion = 6;
      }
        else {
            PRICE = SPRICE;
            MAX_PER_Transtion = 10;
        }
  }

    function setWPrice(uint256 _newPrice) public onlyOwner() {
        WPRICE = _newPrice;
    }

 function setReserveTokens(uint256 _quantity) public onlyOwner {
        reserve=_quantity;
    }

  function getStatus()public view returns(uint){
      return status;
  }
  function getPrice(uint256 _quantity) public view returns (uint256) {
       
        return _quantity*PRICE;
    }

 function mintReserveTokens(uint quantity) public onlyOwner {
        require(quantity <= reserve, "The quantity exceeds the reserve.");
        reserve -= quantity;
        _safeMint(msg.sender, quantity);

    }

  function giveaway(address a, uint q)public onlyOwner{
    require(totalSupply() + q <= collectionSize, "reached max supply");
    require(q <= MAX_PER_Transtion,"can not mint this many");
    _safeMint(a, q);
  }
}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
    require(_exists(tokenId),"ERC721Metadata: URI query for nonexistent token");
    if(_revelNFT){
    string memory baseURI = _baseURI();
    uint256 tokenID = tokenId + 1;
    return
      bytes(baseURI).length > 0
        ? string(abi.encodePacked(baseURI, "/", tokenID.toString(), ".json")) : "";
        } else {
            return _uriBeforeRevel;
        }
  }
//   string(abi.encodePacked(baseURI, tokenId.toString()))