contract RileyReidDAO is ERC721A, Ownable, ReentrancyGuard {

    using Strings for uint256;

    string private baseURI = "";

    bool public isSaleActive = true;

    uint256 public maxFreeMintsPerTX = 1;
    uint256 public maxMintsPerTX = 10;

    uint256 public maxSupply = 3333;
    uint256 public price = 0.01 ether;

    uint256 public maxFree = 333;

    // ============ ACCESS CONTROL/SANITY MODIFIERS ============

    modifier checkSaleActive() {
        require(isSaleActive, "SALE_CLOSED");
        _;
    }

    modifier checkStock(uint256 noOfTokens) {
        require(totalSupply() + noOfTokens <= maxSupply, "SOLD_OUT");
        _;
    }

    modifier checkFreeMaxMints(uint256 noOfTokens) {
        require(noOfTokens <= maxFreeMintsPerTX, "MAX_FREE_MINTS");
        _;
    }

    modifier checkMaxMints(uint256 noOfTokens) {
        require(noOfTokens <= maxMintsPerTX, "MAX_MINTS");
        _;
    }

    modifier checkPayment(uint256 noOfTokens) {
        require((price * noOfTokens) <= msg.value, "INVALID_ETH_VALUE");
        _;
    }

    modifier checkFreeMints() {
        require(totalSupply() <= maxFree, "FREE_SOLD_OUT");
        _;
    }

	constructor() ERC721A("Riley Reid DAO", "RILEYDAO", 50, maxSupply) {}


    // ============ PUBLIC FUNCTIONS FOR MINTING ============

    function mint(uint256 noOfTokens)
        external
        payable
        nonReentrant
        checkSaleActive
        checkStock(noOfTokens)
        checkMaxMints(noOfTokens)
        checkPayment(noOfTokens)
    {
        _safeMint(msg.sender, noOfTokens);
    }

    function freeMint(uint256 noOfTokens)
        external
        nonReentrant
        checkSaleActive
        checkStock(noOfTokens)
        checkFreeMaxMints(noOfTokens)
        checkFreeMints
    {
        _safeMint(msg.sender, noOfTokens);
    }


    // ============ PUBLIC READ-ONLY FUNCTIONS ============

    function getBaseURI() external view returns (string memory) {
        return baseURI;
    }

	// ============ OWNER-ONLY ADMIN FUNCTIONS ============

    function setBaseURI(string memory _baseURI) external onlyOwner {
        baseURI = _baseURI;
    }

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

	function setPrice(uint256 newPrice) external onlyOwner {
		price = newPrice;
	}

	function setMaxFree(uint256 newMaxFree) external onlyOwner {
		maxFree = newMaxFree;
	}

	function withdraw() external onlyOwner {
		payable(msg.sender).transfer(address(this).balance);
	}

    // ============ FUNCTION OVERRIDES ============

	/**
	* @dev See {IERC721Metadata-tokenURI}.
	*/
	function tokenURI(uint256 tokenId)
		public
		view
		virtual
		override
		returns (string memory)
	{
		require(
		_exists(tokenId),
		"ERC721Metadata: URI query for nonexistent token"
		);

        return
            string(abi.encodePacked(baseURI, tokenId.toString(), ".json"));
	}


}
function setBaseURI(string memory _baseURI) external onlyOwner {
    baseURI = _baseURI;
}

// ============ OWNER-ONLY ADMIN FUNCTIONS ============