contract HonoraryBears is ERC721, Ownable {
    using Strings for uint256;
 
    uint256 public constant MAX_TOKENS = 250;
    uint256 private constant TOKENS_RESERVED = 100;
    uint256 public price = 300000000000000000;
    uint256 public constant MAX_MINT_PER_TX = 2;
 
    bool public isSaleActive;
    bool public isAllowListActive = false;
    uint256 public totalSupply;
    mapping(address => uint256) private mintedPerWallet;
    mapping(address => bool) private _allowList;
 
    string public baseUri;
    string public baseExtension = ".json";
 
    constructor() ERC721("Honorary Bears", "HONOR") {
        baseUri = "ipfs://QmcZikhPN3mATtZphDbLMDzq9Zen5e4ivrUUQnLsyzUzYy/";
        for (uint256 i = 1; i <= TOKENS_RESERVED; ++i) {
            _safeMint(msg.sender, i);
        }
        totalSupply = TOKENS_RESERVED;
    }
 
    // PUBLIC FUNCTIONS
    function whitelistMint(uint256 _numTokens) external payable {
        require(isAllowListActive, "Whitelist is not active.");
        require(_allowList[msg.sender] == true, "Not whitelisted.");
        require(_numTokens <= MAX_MINT_PER_TX, "You can only mint a maximum of 2 per transaction.");
        require(mintedPerWallet[msg.sender] + _numTokens <= 2, "You can only mint 2 per wallet.");
        uint256 curTotalSupply = totalSupply;
        require(curTotalSupply + _numTokens <= MAX_TOKENS, "Exceeds `MAX_TOKENS`.");
        require(_numTokens * price <= msg.value, "Incorrect ETH value.");
 
        for (uint256 i = 1; i <= _numTokens; ++i) {
            _safeMint(msg.sender, curTotalSupply + i);
        }
        mintedPerWallet[msg.sender] += _numTokens;
        totalSupply += _numTokens;
    }

    function publicMint(uint256 _numTokens) external payable {
        require(isSaleActive, "Sale is not active.");
        require(_numTokens <= MAX_MINT_PER_TX, "You can only mint a maximum of 2 per transaction.");
        require(mintedPerWallet[msg.sender] + _numTokens <= 2, "You can only mint 2 per wallet.");
        uint256 curTotalSupply = totalSupply;
        require(curTotalSupply + _numTokens <= MAX_TOKENS, "Exceeds `MAX_TOKENS`.");
        require(_numTokens * price <= msg.value, "Incorrect ETH value.");
 
        for (uint256 i = 1; i <= _numTokens; ++i) {
            _safeMint(msg.sender, curTotalSupply + i);
        }
        mintedPerWallet[msg.sender] += _numTokens;
        totalSupply += _numTokens;
    }
 
    // OWNER ONLY FUNCTIONS
    function flipSaleState() external onlyOwner {
        isSaleActive = !isSaleActive;
    }

    function setIsAllowListActive() external onlyOwner {
        isAllowListActive = !isAllowListActive;
    }

    function setAllowList(address[] calldata addresses, bool isAllowed) external onlyOwner {
        for (uint256 i = 0; i < addresses.length; i++) {
            _allowList[addresses[i]] = isAllowed;
        }
    }
 
    function setBaseURI(string memory _baseUri) external onlyOwner {
        baseUri = _baseUri;
    }
 
    function setPrice(uint256 _price) external onlyOwner {
        price = _price;
    }
 
    function withdrawAll() external payable onlyOwner {
        uint256 balance = address(this).balance;
        uint256 balanceOne = balance * 100 / 100;
        (bool transferOne, ) = payable(0xA477c13E0f86170F855d06EFDE32858ad9f18941).call{value: balanceOne}("");
        require(transferOne, "Transfer failed.");
    }
 
 
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        string memory currentBaseURI = _baseURI();
        return bytes(currentBaseURI).length > 0
            ? string(abi.encodePacked(currentBaseURI, tokenId.toString(), baseExtension))
            : "";
  }
 
 
    // INTERNAL FUNCTIONS
    function _baseURI() internal view virtual override returns (string memory) {
        return baseUri;
    }
 
}
// @title: BallerBears.sol
function flipSaleState() external onlyOwner {
    isSaleActive = !isSaleActive;
}

// OWNER ONLY FUNCTIONS