contract BloodShedBearsTokenGenerator is ERC721Enum, Ownable, Pausable {
    using Strings for uint256;

    uint256 constant private maxSupply = 7000;
    uint256 private teamReserveAvailableMints = 100;
    uint256 private cost = 50000 ether;
    address public bloodTokenContract = 0x0000000000000000000000000000000000000000;

    string private baseURI;

    constructor(
        string memory _initBaseURI
    ) ERC721P("Bloodshed Bears TokenGenerator", "BSBTG") {
        setBaseURI(_initBaseURI);
        pause();
    }

    // internal
    function _baseURI() internal view virtual returns (string memory) {
        return baseURI;
    }

    function setBloodTokenContract(address contractAddress_) external onlyOwner {
        bloodTokenContract = contractAddress_;
    }

    function setCost(uint256 _newCost) external onlyOwner {
        cost = _newCost;
    }

    function mint(uint256 mintAmount_) external payable whenNotPaused {
        uint256 totalSupply = totalSupply();

        require(totalSupply + mintAmount_ <= maxSupply, "TOO MANY");
        require(IBloodTokenContract(bloodTokenContract).walletsBalances(msg.sender) >= mintAmount_ * cost, "NOT ENOUGH");
        IBloodTokenContract(bloodTokenContract).spend(msg.sender, mintAmount_ * cost);

        for (uint256 i = 0; i < mintAmount_; i++) {
            _safeMint(msg.sender, totalSupply + i);
        }

        delete totalSupply;
    }

    function tokenURI(uint256 _tokenId) external view virtual override returns (string memory) {
        require(_exists(_tokenId), "ERC721Metadata: Nonexistent token");
        string memory currentBaseURI = _baseURI();
        return bytes(currentBaseURI).length > 0	? string(abi.encodePacked(currentBaseURI, _tokenId.toString(), ".json")) : "";
    }

    // admin minting
    function reserve(address _to, uint256 _reserveAmount) public onlyOwner {
        uint256 supply = totalSupply();
        require(
            _reserveAmount > 0 && _reserveAmount <= teamReserveAvailableMints,
            "Not enough reserve left for team"
        );
        for (uint256 i = 0; i < _reserveAmount; i++) {
            _safeMint(_to, supply + i);
        }
        teamReserveAvailableMints -= _reserveAmount;
    }

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

    function isOwnerOfBatch(uint256[] calldata tokenIds_, address address_) external view returns (bool) {
        bool ownership = true;

        for (uint256 i = 0; i < tokenIds_.length; ++i) {
            ownership = ownership && (ownerOf(tokenIds_[i]) == address_);
        }

        return ownership;
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }
}
function _baseURI() internal view virtual returns (string memory) {
    return baseURI;
}

// internal