contract MetaComedyClub is ERC1155, Ownable {
    uint256 private constant GENESIS_ID = 0;
    uint256 private constant ROOM_101_ID = 1;
    uint256 private constant MAX_GENESIS = 5000;
    uint256 private constant MAX_ROOM_101 = 101;

    uint256 public mintPrice = 101000000000000000; // 0.101 eth

    // Club Rules
    mapping(uint256 => uint256) public maxSupply;
    mapping(uint256 => uint256) public totalSupply;
    // Guest List
    mapping(address => bool) public room101Allow;
    // URIs
    mapping(uint256 => string) private uris;

    // Mint Guard
    bool private minting;

    address public clubWallet;
    address public devWallet;

    constructor() ERC1155('') {
        maxSupply[GENESIS_ID] = MAX_GENESIS;
        maxSupply[ROOM_101_ID] = MAX_ROOM_101;
    }

    // returns the IPFS address of the Magazine Issue once set
    function uri(uint256 tokenId) public view override returns (string memory) {
        return (uris[tokenId]);
    }

    // sets the IPFS address of the Magazine Issue
    function setTokenURI(uint256 tokenId, string memory newUri)
        external
        onlyOwner
    {
        uris[tokenId] = newUri;
    }

    function mintGenesis(uint16 amount) external payable {
        require(minting, "Minting must be active");
        uint256 currentSupply = totalSupply[GENESIS_ID];
        uint256 availableSupply = maxSupply[GENESIS_ID] - currentSupply;

        require(amount > 0 && amount <= 3, "Max 3 NFTs per transaction");
        require(availableSupply >= amount, "Mint would exceed max supply");

        require(msg.value >= mintPrice * amount, "Ether value sent is not correct");

        totalSupply[GENESIS_ID] += amount;

        _mint(_msgSender(), GENESIS_ID, amount, '');
    }

    function mintRoom101() external {
        require(minting, "Minting must be active");
        require(
            totalSupply[ROOM_101_ID] < maxSupply[ROOM_101_ID],
            "Mint would exceed max supply"
        );
        require(room101Allow[_msgSender()], "Not on the list");

        totalSupply[ROOM_101_ID] += 1;
        room101Allow[_msgSender()] = false;

        _mint(_msgSender(), ROOM_101_ID, 1, '');
    }

    function communityReserve(uint256 amount, uint256 tokenId) external onlyOwner {
        uint256 currentSupply = totalSupply[tokenId];
        uint256 availableSupply = maxSupply[tokenId] - currentSupply;

        require(!minting, "Minting is in progress");
        require(availableSupply >= amount, "Not enough remaining");

        totalSupply[tokenId] += amount;

        _mint(owner(), tokenId, amount, '');
    }

    function withdraw() external onlyOwner {
        require(
            address(clubWallet) != address(0),
            "No club wallet"
        );
        require(
            address(devWallet) != address(0),
            "No dev wallet"
        );

        require(address(this).balance > 0, "Balance is 0");

        uint256 balance = address(this).balance;

        payable(clubWallet).transfer((balance * 850) / 1000);
        payable(devWallet).transfer((balance * 150) / 1000);
    }

    function setClubWallet(address _clubWallet) external onlyOwner {
        clubWallet = _clubWallet;
    }

    function setDevWallet(address _devWallet) external onlyOwner {
        devWallet = _devWallet;
    }

    function setMinting(bool _minting) external onlyOwner {
        minting = _minting;
    }

    function setMintPrice(uint256 _mintPrice) external onlyOwner {
        mintPrice = _mintPrice;
    }

    function setRoom101Allow(address[] calldata addresses, bool allowed)
        external
        onlyOwner
    {
        for (uint256 i; i < addresses.length; i++) {
            room101Allow[addresses[i]] = allowed;
        }
    }
}
function uri(uint256 tokenId) public view override returns (string memory) {
    return (uris[tokenId]);
}

// returns the IPFS address of the Magazine Issue once set