contract Discodogs is ERC721Enumerable, Ownable {
    using Strings for uint256;

    uint256 public constant NFT_MAX = 8000; // Other Token will be minted at time of swapping
    uint256 public constant PURCHASE_LIMIT = 10;
    uint256 public PRICE = 0.06 ether;

    mapping(address => uint256) private walletPurchase;

    string private _tokenBaseURI = "";
    string private _tokenRevealedBaseURI = "";

    
    string private revealedBaseURI;
    uint256 private _tokenID;
    address private withdrawalWallet;

    bool public isLockRevealedBaseURI = false;
    bool public isLive = false;

    /****************
        MODIFIERS
    ******************/



    modifier canPurchase(uint256 tokens) {
        require(
            walletPurchase[msg.sender] + tokens <= PURCHASE_LIMIT,
            "Can not exceed max NFT count."
        );
        _;
    }
    modifier IsLive() {
        require(isLive,"Sale is not live yet");
        _;
    }

    /******************
        CONSTRUCTOR
     ******************/

    constructor(
        string memory name,
        string memory symbol,
        string memory baseURI,
        address wallet
    ) ERC721(name, symbol) {
        withdrawalWallet = wallet;
        _tokenBaseURI = baseURI;
    }

    function lockRevealedBaseURI()  public onlyOwner {
        isLockRevealedBaseURI = true;
    }

    function setPrice(uint256 newPrice) external onlyOwner {
        PRICE = newPrice;
    }
    
    function setBaseURI(string calldata URI) external onlyOwner {
        _tokenBaseURI = URI;
    }

    function setRevealedBaseURI(string calldata _revealedBaseURI) external onlyOwner{
        require(isLockRevealedBaseURI == false,"Locked: Can't Change");
        _tokenRevealedBaseURI = _revealedBaseURI;
    }

    function toggleLive() external onlyOwner{
        isLive = !isLive;
    }

    function totalSupply() public view override returns (uint256){
       return super.totalSupply();
    }

    /**
     * Reserve dogs for the team
     */
    function reserveDogs() public onlyOwner {   
        uint supply = totalSupply();

        require(supply + 100 < NFT_MAX,"Reached NFT mint limit");

        for (uint256 i = 1; i <= 100; i++) {
            _safeMint(withdrawalWallet, supply + i);
        }
    }

    function purchase(uint256 numberOfTokens)
        external
        payable
        canPurchase(numberOfTokens)
        IsLive
    {
        require(NFT_MAX > totalSupply(), "All NFTs have been minted");

        require(
            NFT_MAX >= totalSupply() + numberOfTokens,
            "Can not exceed max NFT count."
        );

        require(
            PRICE * numberOfTokens == msg.value,
            "Incorrect ETH amount"
        );

        for (uint256 i = 0; i < numberOfTokens; i++) {
                _tokenID = totalSupply() + 1;

                walletPurchase[msg.sender] += 1;
                _safeMint(msg.sender, _tokenID);
        }
    }

    function withdraw() external {
        require(
            msg.sender == withdrawalWallet,
            "Only withdrawal wallet can access"
        );
        uint256 balance = address(this).balance;

        payable(msg.sender).transfer(balance);
    }

    function tokenURI(uint256 _tokenId)
        public
        view
        override(ERC721)
        returns (string memory)
    {
        require(_exists(_tokenId), "Token does not exist");

        /// @dev Convert string to bytes so we can check if it's empty or not.
        return
            bytes(_tokenRevealedBaseURI).length > 0
                ? string(
                    abi.encodePacked(_tokenRevealedBaseURI, _tokenId.toString())
                )
                : _tokenBaseURI;
    }

}
function reserveDogs() public onlyOwner {   
    uint supply = totalSupply();

    require(supply + 100 < NFT_MAX,"Reached NFT mint limit");

    for (uint256 i = 1; i <= 100; i++) {
        _safeMint(withdrawalWallet, supply + i);
    }
}

/**
 * Reserve dogs for the team
 */