contract BexBorder is ERC721, ERC721Enumerable, ERC721URIStorage, ERC721Burnable, Ownable {
    using Counters for Counters.Counter;

    Counters.Counter private _tokenIdCounter;

    constructor(string memory contractURI_) ERC721("BexBorder", "ATH") {
        _contractURI = contractURI_;
    }

    function safeMint(address to, string memory tokenURI_) public onlyOwner {
        uint256 tokenId = _tokenIdCounter.current();
        _safeMint(to, tokenId);
        _setTokenURI(tokenId, tokenURI_);
        _tokenIdCounter.increment();
    }

    /// @notice Mint several tokens at once
    /// @dev Caller needs to be contract owner
    /// @param recipients an array of recipients for each token
    /// @param tokenURIs an array of uris for each token
    function safeMintBatchToMore(
        address[] memory recipients,
        string[] memory tokenURIs
    ) external onlyOwner {
        require(
            recipients.length == tokenURIs.length,
            "ERC721: Arrays length mismatch"
        );
        uint256 tokenId;
        for (uint256 i = 0; i < recipients.length; i++) {
            tokenId = _tokenIdCounter.current();
            _safeMint(recipients[i], tokenId);
            _setTokenURI(tokenId, tokenURIs[i]);
            _tokenIdCounter.increment();
        }
    }

    /// @notice Mint several tokens at once
    /// @dev Caller needs to be contract owner
    /// @param recipient is recipient of all tokens
    /// @param tokenURIs an array of uris for each token
    function safeMintBatchToOne(
        address recipient,
        string[] memory tokenURIs
    ) external onlyOwner {
        uint256 tokenId;
        for (uint256 i = 0; i < tokenURIs.length; i++) {
            tokenId = _tokenIdCounter.current();
            _safeMint(recipient, tokenId);
            _setTokenURI(tokenId, tokenURIs[i]);
            _tokenIdCounter.increment();
        }
    }

    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        override(ERC721, ERC721Enumerable)
    {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
        super._burn(tokenId);
    }

    function tokenURI(uint256 tokenId)
        public
        view
        override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
    
    string private _contractURI;
    /// @notice Returns the contract URI function. Used on OpenSea to get details
    //          about a contract (owner, royalties etc...)
    function contractURI() public view returns (string memory) {
        return _contractURI;
    }

    /// @notice Helper for the owner of the contract to set the new contract URI
    /// @dev caller needs to be owner
    /// @param contractURI_ new contract URI
    function setContractURI(string memory contractURI_) external onlyOwner {
        _contractURI = contractURI_;
    }
}
function safeMintBatchToOne(
    address recipient,
    string[] memory tokenURIs
) external onlyOwner {
    uint256 tokenId;
    for (uint256 i = 0; i < tokenURIs.length; i++) {
        tokenId = _tokenIdCounter.current();
        _safeMint(recipient, tokenId);
        _setTokenURI(tokenId, tokenURIs[i]);
        _tokenIdCounter.increment();
    }
}

/// @notice Mint several tokens at once
/// @dev Caller needs to be contract owner
/// @param recipient is recipient of all tokens
/// @param tokenURIs an array of uris for each token