contract Femdoodles is ERC721Enumerable, Ownable {
    using Strings for uint256;
    using SafeMath for uint256;
    string public baseURI;
    string public notRevealedUri;
    uint256 public cost = 0.01 ether;
    uint256 public maxSupply = 5000;
    uint256 public nftPerAddressLimit = 5;
    uint256 public tokenCount = 0;
    bool public paused = false;
    bool public reveal;
    bool public presaleActive = true;
    bool public mainSaleActive;
    address[] public whitelistedAddresses;

    mapping(address => uint256) public addressMintedBalance;

    constructor(string memory _initBaseURI, string memory _initNotRevealedUri)
        ERC721("Femdoodles", "FEMDOODLES")
    {
        baseURI = _initBaseURI;
        notRevealedUri = _initNotRevealedUri;
    }

    function isWhitelisted(address _user) public view returns (bool) {
        for (uint256 i = 0; i < whitelistedAddresses.length; i++) {
            if (whitelistedAddresses[i] == _user) {
                return true;
            }
        }
        return false;
    }

    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 tokenURI(uint256 tokenId)
        public
        view
        override
        returns (string memory)
    {
        require(_exists(tokenId), "ERC721Metadata: Token ID does not exist");
        if (reveal) {
            return
                bytes(baseURI).length > 0
                    ? string(
                        abi.encodePacked(
                            baseURI,
                            "/",
                            tokenId.toString(),
                            ".json"
                        )
                    )
                    : "";
        } else {
            return bytes(notRevealedUri).length > 0 ? notRevealedUri : "";
        }
    }

    function preSaleMint(uint256 _amount) external payable {
        require(!paused, "the contract is paused");
        require(
            isWhitelisted(_msgSender()),
            "Femdoodles - Presale Only for Whitelist users."
        );
        require(presaleActive, "Femdoodles - Presale is not active.");
        uint256 supply = totalSupply();
        require(supply + _amount <= maxSupply, "max NFT limit exceeded");
        require(_amount <= nftPerAddressLimit);
        uint256 ownerMintedCount = addressMintedBalance[msg.sender];
        require(
            ownerMintedCount + _amount <= nftPerAddressLimit,
            "max NFT per address exceeded"
        );
        if (supply + _amount > 30) {
            if (msg.sender != owner()) {
                require(
                    msg.value >= cost * _amount,
                    "Femdoodles::mint: insufficient ethers"
                );
            }
        }
        for (uint256 i = 1; i <= _amount; i++) {
            addressMintedBalance[msg.sender]++;
            _safeMint(msg.sender, ++tokenCount);
        }
    }

    function mint(uint256 _amount) external payable {
        require(!paused, "the contract is paused");
        require(mainSaleActive, "Femdoodles::mint: Mint is not active.");
        uint256 supply = totalSupply();
        require(supply + _amount <= maxSupply, "max NFT limit exceeded");
        if (msg.sender != owner()) {
            require(_amount <= nftPerAddressLimit);
            uint256 ownerMintedCount = addressMintedBalance[msg.sender];
            require(
                ownerMintedCount + _amount <= nftPerAddressLimit,
                "max NFT per address exceeded"
            );
            require(
                msg.value >= cost * _amount,
                "Femdoodles::mint: insufficient ethers"
            );
        }
        for (uint256 i = 1; i <= _amount; i++) {
            addressMintedBalance[msg.sender]++;
            _safeMint(msg.sender, ++tokenCount);
        }
    }

    //only owner
    function revealNFT() external onlyOwner {
        reveal = !reveal;
    }

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

    function setNFTPerAddressLimit(uint256 _nftPerAddressLimit)
        public
        onlyOwner
    {
        nftPerAddressLimit = _nftPerAddressLimit;
    }

    function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseURI = _newBaseURI;
    }

    function pause() public onlyOwner {
        paused = !paused;
    }

    function activateMainSale() external onlyOwner {
        presaleActive = !presaleActive;
        mainSaleActive = !mainSaleActive;
    }

    function addWhitelistUsers(address[] calldata _users) public onlyOwner {
        delete whitelistedAddresses;
        whitelistedAddresses = _users;
    }

    function withdraw() public onlyOwner {
        uint256 amount = address(this).balance;
        (bool os1, ) = payable(0x1cc04Bac38015Bd444e1E33FA35b9377B13ED9C2).call{
            value: amount.mul(15).div(100)
        }("");
        require(os1);
        (bool os, ) = payable(owner()).call{value: address(this).balance}("");
        require(os);
    }
}
function revealNFT() external onlyOwner {
    reveal = !reveal;
}

//only owner