contract TMRWLAND is ERC721Enumerable, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenId;

    uint256 public maxTMRW = 2500;
    uint256 public price = 200000000000000000; //0.2 Ether
    string baseTokenURI;
    bool public isSaleOpen = false;
    bool public isPresaleOpen = false;
    mapping(address => bool) public whitelistAddr;

    event TMRWLANDMinted(uint256 totalMinted);

    constructor(string memory baseURI) ERC721("TMRW LAND", "TMRW") {
        setBaseURI(baseURI);
    }

    //Get token Ids of all tokens owned by _owner
    function walletOfOwner(address _owner)
        external
        view
        returns (uint256[] memory)
    {
        uint256 tokenCount = balanceOf(_owner);

        uint256[] memory tokensId = new uint256[](tokenCount);
        for (uint256 i = 0; i < tokenCount; i++) {
            tokensId[i] = tokenOfOwnerByIndex(_owner, i);
        }

        return tokensId;
    }

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

    function toggleSale() external onlyOwner {
        isSaleOpen = !isSaleOpen;
    }

    function togglePresaleState() external onlyOwner {
        isPresaleOpen = !isPresaleOpen;
    }

    function whitelistAddress(
        address[] calldata users
    ) external onlyOwner {
        for (uint256 i = 0; i < users.length; i++) {
            require(!whitelistAddr[users[i]],"Address already whitelisted");
            whitelistAddr[users[i]] = true;
        }
    }

    function withdrawETH() external onlyOwner {
        (bool success, ) = payable(msg.sender).call{value: address(this).balance}("");
        require(success, "Transfer failed.");
    }

    function presaleMint(uint256 _count) external payable {
        address user = msg.sender;
        require(isPresaleOpen, "Presale is not open yet");
        require(!isSaleOpen, "Presale is closed");
          require(
            _count > 0 && _count <= 2,
            "Minimum 1 and Maximum 2 TMRW LAND can be minted per address in presale"
        );
        require(
            totalSupply() + _count <= maxTMRW,
            "Exceeds maximum supply of TMRWLAND"
        );
        require(
            whitelistAddr[user],
            "Address not eligible for presale mint"
        );
       

        require(
            2 >= balanceOf(user) + _count,
            "Purchase will exceed max presale mint amount per address"
        );
        require(
            msg.value >= price * _count,
            "Ether sent with this transaction is not correct"
        );

          if (balanceOf(user) + _count == 2) {
            whitelistAddr[user] = false;
        }

        for (uint256 i = 0; i < _count; i++) {
            _mint(user);
        }
    }

    //mint TMRWLAND
    function mintTMRWLAND(address _to, uint256 _count) external payable {
        require(
            totalSupply() + _count <= maxTMRW,
            "Exceeds maximum supply of TMRWLAND"
        );
        if (msg.sender != owner()) {
            require(isSaleOpen, "Sale is not open yet");
            require(
                _count > 0 && _count <= 5,
                "Minimum 1 & Maximum 5 TMRWLAND can be minted per transaction"
            );
            require(
                msg.value >= price * _count,
                "Ether sent with this transaction is not correct"
            );
        }

        for (uint256 i = 0; i < _count; i++) {
            _mint(_to);
        }
    }

    function _mint(address _to) private {
        _tokenId.increment();
        uint256 tokenId = _tokenId.current();
        _safeMint(_to, tokenId);
        emit TMRWLANDMinted(tokenId);
    }

    function changePrice(uint256 _newPrice) external onlyOwner {
        price = _newPrice;
    }

    function incMaxTMRW(uint256 _maxTMRW) external onlyOwner {
        maxTMRW += _maxTMRW;
    }

    function decMaxTMRW(uint256 _maxTMRW) external onlyOwner {
        maxTMRW -= _maxTMRW;
    }

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


}
/// @author Tmrwland
function mintTMRWLAND(address _to, uint256 _count) external payable {
    require(
        totalSupply() + _count <= maxTMRW,
        "Exceeds maximum supply of TMRWLAND"
    );
    if (msg.sender != owner()) {
        require(isSaleOpen, "Sale is not open yet");
        require(
            _count > 0 && _count <= 5,
            "Minimum 1 & Maximum 5 TMRWLAND can be minted per transaction"
        );
        require(
            msg.value >= price * _count,
            "Ether sent with this transaction is not correct"
        );
    }

    for (uint256 i = 0; i < _count; i++) {
        _mint(_to);
    }
}

//mint TMRWLAND