contract APEDippies is ERC721A, Ownable, ReentrancyGuard {
    
    uint256 public collectionSize = 2222;
    uint256 public amountForDevs = 20;
    uint256 public maxPerAddress = 5;
    uint256 public price;
    bool public contractLocked = true;

    //whitelist tree 
    bytes32 public root;

    constructor() ERC721A("Ape Dippies", "APEDippies") {}
     
    function setRoot(bytes32 _newRoot) external onlyOwner {
        root = _newRoot;
    }
    
    function setOpenSale(bool locked) external onlyOwner {
        contractLocked = locked;
    }

    //set the price
    function setPice(uint256 newPrice) external onlyOwner {
        price = newPrice;
    }

    function MintedAmount() public view returns (uint256) {
        return totalSupply();
    }

    //amount minted by user
    function numberMinted(address _user) public view returns (uint256) {
        return _numberMinted(_user);
    }

    function Mint(uint256 quantity, bytes32[] memory _merkleProof) external payable {
        //verify if the mint is open
        require(contractLocked == false, "Contract is locked");
        require(totalSupply() <= collectionSize, "Reached max supply!");

        //verify if the msg.sender is a part of the whitelist tree 
        bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
        require(MerkleProof.verify(_merkleProof, root, leaf), "You are not whitelisted");

        //verify if the minting amount is <= maxPerAddress
        require(totalSupply() + quantity <= collectionSize, "You are reaching the max supply available!");
        require(numberMinted(msg.sender) + quantity <= maxPerAddress, "Cant mint more than 5!");
        require(numberMinted(msg.sender) <= maxPerAddress,"You reached the max amount available for this wallet!");
        
        //verify if the msg.value >= price * minting quantity
        require(msg.value >= quantity * price,"You are not sending enough eth!");

        //mint the selected amount
        _safeMint(msg.sender, quantity);
    }


    //marketing etc
    function _mint(uint256 quantity) external payable onlyOwner {
        require(totalSupply() + quantity <= collectionSize,"You are reaching the max supply available!");
        require(numberMinted(msg.sender) <= amountForDevs, "Cant mint more!");
        require(numberMinted(msg.sender) + quantity <= amountForDevs, "Cant mint more!");

        _safeMint(msg.sender, quantity);
    }

    //setting metadata URI
    string private _baseTokenURI;

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

    function setBaseURI(string calldata baseURI) external onlyOwner {
        _baseTokenURI = baseURI;
    }

    function withdraw() external onlyOwner nonReentrant {
        (bool success, ) = msg.sender.call{value: address(this).balance}("");
        require(success, "Transfer failed.");
    }
}
function numberMinted(address _user) public view returns (uint256) {
    return _numberMinted(_user);
}

//amount minted by user