contract SussyKneelsNFT is ERC721, Ownable {

    // Store base URI, update each mint/batchMint to include new metadata
    string private _baseUri = "";

    uint16 private _tokenIdCounter = 0;

    // WARNING: setting this to true will permanently lock minting.
    bool private _supplyIsLocked = false;


    constructor() ERC721("Sussy Kneels", "KNEEL") {
        // mint first drop on deployment.
        safeMintBatch(owner(), "QmbCttPNA6b8hTyp8XJtAwAfJCi1cCUTXer4V8M5WdoqpZ/", 12);
    }

    // URI will be returned as baseUri/tokenId
    function safeMint(address to, string memory baseUri) public onlyOwner {
        require(!_supplyIsLocked, "SussyKneelsNFT: Supply has been permanently locked, no minting is allowed.");
        uint16 tokenId = _tokenIdCounter + 1;
        _safeMint(to, tokenId);
        _baseUri = baseUri;
        _tokenIdCounter = tokenId;
    }

    // URIs will be returned baseUri/tokenId
    function safeMintBatch(address to, string memory baseUri, uint16 numTokens) public onlyOwner {
        require(!_supplyIsLocked, "SussyKneelsNFT: Supply has been permanently locked, no minting is allowed.");
        uint16 counter = _tokenIdCounter;
        for(uint16 i=0; i<numTokens; i++) {
            counter++;
            _safeMint(to, counter);
        }
        _baseUri = baseUri;
        _tokenIdCounter = counter;
    }

    // WARNING: This function will permanently lock supply, minting, and metadata.
    // Normal functionality for all previously minted Sussy Kneels will be retained.
    // Sussy Kneels will hold a community vote before ever locking minting.
    function lockSupply() public onlyOwner {
        _supplyIsLocked = true;
    }

    function totalSupply() public view returns (uint16) {
        return _tokenIdCounter;
    }

    function supplyLock() public view returns (bool) {
        return _supplyIsLocked;
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(tokenId != 0, "SussyKneelsNFT: tokenId 0 does not exist, 1 is first tokenId.");
        require(tokenId < _tokenIdCounter + 1, "SussyKneelsNFT: tokenId does not exist, it is larger than total supply.");
        return string(abi.encodePacked(_baseUri, Strings.toString(tokenId)));
    }
}
function safeMint(address to, string memory baseUri) public onlyOwner {
    require(!_supplyIsLocked, "SussyKneelsNFT: Supply has been permanently locked, no minting is allowed.");
    uint16 tokenId = _tokenIdCounter + 1;
    _safeMint(to, tokenId);
    _baseUri = baseUri;
    _tokenIdCounter = tokenId;
}

// URI will be returned as baseUri/tokenId