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

  string public uriPrefix = "";
  string public uriSuffix = ".json";
  string public hiddenMetadataUri;
  
  uint256 public cost = 0.01 ether;
  uint256 public maxSupply = 3333;
  uint256 public maxMintAmountPerTx = 100;
  uint256 public nftMintPerAddressLimit = 100;
  mapping (address => uint256) public ownerTokenMapping;


  bool public paused = false;
  bool public revealed = false;

  constructor() ERC721A("0xClones", "0xCL") {
    setHiddenMetadataUri("ipfs://QmZXjDhKsn3YTXviwDEBDPhjonyveLaHdppCkCatANgQRS/Reveal.json");
  }

  modifier mintCompliance(uint256 _mintAmount) {
    require(_mintAmount > 0 && _mintAmount <= maxMintAmountPerTx, "Invalid mint amount!");
    require(_currentIndex + _mintAmount <= maxSupply, "Max supply exceeded!");
    _;
  }

  function mint(uint256 _mintAmount) public payable mintCompliance(_mintAmount) {
    require(!paused, "The contract is paused!");
    require(ownerTokenMapping[msg.sender] + _mintAmount <= nftMintPerAddressLimit, "Max tokens exceeded");
    require(msg.value >= cost * _mintAmount, "Insufficient funds!");
    _safeMint(msg.sender, _mintAmount);
    ownerTokenMapping[msg.sender] += _mintAmount;
  }

  function mintOwner(address _to, uint256 _mintAmount) public mintCompliance(_mintAmount) onlyOwner {
        _safeMint(_to, _mintAmount);
    }
  
  function tokenURI(uint256 _tokenId) public view virtual override returns (string memory){
    require(
      _exists(_tokenId),
      "ERC721AMetadata: URI query for nonexistent token"
    );

    if (revealed == false) {
      return hiddenMetadataUri;
    }

    string memory currentBaseURI = _baseURI();
    return bytes(currentBaseURI).length > 0
        ? string(abi.encodePacked(currentBaseURI, _tokenId.toString(), uriSuffix))
        : "";
  }

  function setRevealed(bool _state) public onlyOwner {
    revealed = _state;
  }

  function setCost(uint256 _cost) public onlyOwner {
    cost = _cost;
  }

  function setMaxMintAmountPerTx(uint256 _maxMintAmountPerTx) public onlyOwner {
    maxMintAmountPerTx = _maxMintAmountPerTx;
  }

  function setNftMintPerAddressLimit(uint256 _newNftMintPerAddressLimit) public onlyOwner {
    nftMintPerAddressLimit = _newNftMintPerAddressLimit;
  }

  function setHiddenMetadataUri(string memory _hiddenMetadataUri) public onlyOwner {
    hiddenMetadataUri = _hiddenMetadataUri;
  }

  function setUriPrefix(string memory _uriPrefix) public onlyOwner {
    uriPrefix = _uriPrefix;
  }

  function setUriSuffix(string memory _uriSuffix) public onlyOwner {
    uriSuffix = _uriSuffix;
  }

  function setPaused(bool _state) public onlyOwner {
    paused = _state;
  }

  // Withdraw
    


 function withdraw() public onlyOwner {
    (bool os, ) = payable(owner()).call{value: address(this).balance}("");
    require(os);
  }

 

  function _baseURI() internal view virtual override returns (string memory) {
    return uriPrefix;
  }
}
function withdraw() public onlyOwner {
   (bool os, ) = payable(owner()).call{value: address(this).balance}("");
   require(os);
 }

// Withdraw