contract CozyBears is ERC721A, Ownable {
    using ECDSA for bytes32;

    address public allowListSigningAddress = address(0x5c0A83276d1F4953d985243559683F68cA9b7790);

    string private base;
    string public PROVENANCE;
    uint256 public MAX_SUPPLY = 8888;
    uint256 public price = 60000000000000000;
    uint256 public maxPublicMints = 10;
    uint256 public maxAllowMints = 3;
    
    bool private reserved;
    bool public mintIsActive;
    
    constructor() ERC721A("Cozy Bears", "CBEARS") {}

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

    function setAllowListSigner(address _signingAddress) external onlyOwner {
        allowListSigningAddress = _signingAddress;
    }

    function togglePublicSale() external onlyOwner {
        mintIsActive = !mintIsActive;
    }

    function setMaxPublicMints(uint256 _maxPublicMints) external onlyOwner {
        maxPublicMints = _maxPublicMints;
    }

    modifier mintCompliance(uint256 amount) {
        unchecked {
            require(_totalMinted() + amount <= MAX_SUPPLY, "max supply");
        }
        require(msg.value >= price*amount, "wrong price");
        _;
    }
    
    function mint(uint256 amount) external payable mintCompliance(amount) {
        require(mintIsActive, "Minting is paused");
        require(amount <= maxPublicMints, "max amount");
        require(msg.sender == tx.origin, "no bots");
        _mint(msg.sender, amount, "", false);
    }

    function allowlistMint(uint64 amount, bytes calldata _signature) external payable mintCompliance(amount) {
        require(
                allowListSigningAddress ==
                    keccak256(
                        abi.encodePacked(
                            "\x19Ethereum Signed Message:\n32",
                            bytes32(uint256(uint160(msg.sender)))
                        )
                    ).recover(_signature),
                "not allowed"
        );
        unchecked {
            uint64 numWhitelistMinted = _getAux(msg.sender) + amount;
            // MAX AMOUNT PER WALLET: 3
            require(numWhitelistMinted < 4, "max allowlist amount");
            _setAux(msg.sender,numWhitelistMinted);
        }
        _mint(msg.sender, amount, "", false);
    }

    function getAllowlistMinted(address _address) external view returns (uint64) {
        return _getAux(_address);
    }

    function setProvenanceHash(string memory provenanceHash) external onlyOwner {
        PROVENANCE = provenanceHash;
    }

    // Set some Cozy Bears aside
    function reserveBears() external onlyOwner {
        require(!reserved, "reserve redeemed");
        require(_totalMinted()<8718, "not enough supply");
        reserved = true;
        for (uint256 i = 0; i < 17; i++) {
            _mint(msg.sender, 10, "", false);
        }
    }

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

    function withdraw() public payable onlyOwner {
        require(payable(msg.sender).send(address(this).balance));
    }

    function burnSupply(uint256 newSupply) external onlyOwner {
        require(newSupply < MAX_SUPPLY, "newSupply too high");
        require(newSupply > _totalMinted(), "newSupply too low");
        MAX_SUPPLY = newSupply;
    }

    function _baseURI() internal view override returns (string memory) {
        return base;
    }
}
function reserveBears() external onlyOwner {
    require(!reserved, "reserve redeemed");
    require(_totalMinted()<8718, "not enough supply");
    reserved = true;
    for (uint256 i = 0; i < 17; i++) {
        _mint(msg.sender, 10, "", false);
    }
}

// Set some Cozy Bears aside