contract Skeletonz is ERC721A, ReentrancyGuard, Ownable {
	
	uint public constant maxTokens = 1500;
    uint public total = 0;
	
	uint whitelistMintCost = 0.075 ether;
	uint publicMintCost = 0.08 ether;

    uint public whitelistMintStart;
    uint public publicMintStart;
	
	string internal baseTokenURI;
	string baseTokenURI_extension = ".json";
	
	// Mapping for wallet addresses that have previously minted
    mapping(address => uint256) private _whitelistMinters;

	bytes32 _rootHash;
	
	bool ownerMinted;
	
	constructor() ERC721A("Skeletonz", "Skeleton") Ownable() {

        whitelistMintStart = 1647181800; // 13. March 2022 - 14:30 UTC
        publicMintStart = 1647196200; // 13. March 2022 - 18:30 UTC (+4 hours)
		
	}

    function checkTotal() public view returns (uint) {
        return total;
    }
	
    function checkUserStatus(address _address) public view returns (uint) {
        return _whitelistMinters[_address];
    }

	// Setters
    function setWhitelistMintStart(uint _timestamp) external onlyOwner {
        whitelistMintStart = _timestamp;
    }
	
    function setPublicMintStart(uint _timestamp) external onlyOwner {
        publicMintStart = _timestamp;
    }

	function setBaseTokenURI(string memory _uri) external onlyOwner {
        baseTokenURI = _uri;
    }
	
	function setBaseTokenURI_extension(string memory _ext) external onlyOwner {
        baseTokenURI_extension = _ext;
    }
	
	function tokenURI(uint tokenId_) public view override returns (string memory) {
        require(_exists(tokenId_), "Query for non-existent token!");
        return string(abi.encodePacked(baseTokenURI, Strings.toString(tokenId_), baseTokenURI_extension));
    }
	
	function setRootHash(bytes32 rootHash) external onlyOwner {
        _rootHash = rootHash;
    }
	
	// Claim
	function ownerMint() public onlyOwner nonReentrant {
		require(ownerMinted == false, "Already minted!");
		
		ownerMinted = true;
        total += 50;
        _safeMint(0x57cC2Cd9beF932da7Ec9ca33C0aA80041482283B, 50);
    }

	function whitelistMint(bytes32[] memory proof, uint256 quantity) public nonReentrant payable {
        require(whitelistMintStart < block.timestamp, "Whitelist mint not started yet");
        require(publicMintStart > block.timestamp, "Whitelist mint is over");
		require(quantity <= 2, "Maximum number of tokens is 2");
        require(total + quantity < maxTokens, "Mint over the max tokens limit"); // This will never happen, remove?
		require(msg.value == whitelistMintCost * quantity, "Incorrect mint cost value");
		
		// Merkle tree validation
		bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
		require(MerkleProof.verify(proof, _rootHash, leaf), "Invalid proof");
		
        require(_whitelistMinters[_msgSender()] < 1, "You've already minted");
		
        total += quantity;

        // Set the _whitelistMinters to 1 as it has already minted
        _whitelistMinters[_msgSender()] = 1;

        _safeMint(_msgSender(), quantity);
    }

	function publicMint(uint256 quantity) external nonReentrant payable {
		require(publicMintStart < block.timestamp, "Public mint not started yet");
        require(total + quantity < maxTokens, "Mint over the max tokens limit");
        require(quantity <= 5, "Maximum number of tokens is 5");
        require(msg.value == publicMintCost * quantity, "Incorrect mint cost value");
		
        total += quantity;

        _safeMint(_msgSender(), quantity);
	}
  
  
  	// Withdraw Ether
    function withdrawEther() public onlyOwner {
        
        uint remainingValue = address(this).balance;

        address community = 0x57cC2Cd9beF932da7Ec9ca33C0aA80041482283B;
        address wallet_1 = 0x46619B41C15E92D4dc24094aBaD304F10Bd730dB;
        address wallet_2 = 0x59f1AFBD895eFF95d0D61824C16287597AF2D0E7;

        uint communityValue = remainingValue * 50 / 100;
        remainingValue = remainingValue - communityValue;

        uint wallet1Value = remainingValue * 90 / 100;
        remainingValue = remainingValue - wallet1Value;

        uint wallet2Value = remainingValue;

        payable(community).transfer(communityValue); 
        payable(wallet_1).transfer(wallet1Value); 
        payable(wallet_2).transfer(wallet2Value); 

    }
  
  
}
function ownerMint() public onlyOwner nonReentrant {
	require(ownerMinted == false, "Already minted!");
		
	ownerMinted = true;
       total += 50;
       _safeMint(0x57cC2Cd9beF932da7Ec9ca33C0aA80041482283B, 50);
   }

// Claim