contract BlindBox is ERC721Enumerable, ReentrancyGuard, Ownable {

        string[] private weapons = [
        "0",
        "1",
        "2",
        "3",
        "4",
        "5",
        "6",
        "7",
        "8",
        "9"
    ];
    
 
    function random(string memory input) internal pure returns (uint256) {
        return uint256(keccak256(abi.encodePacked(input)));
    }
    
    function getNumber1(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "WEAPON", weapons);
    }
    
    function getNumber2(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "CHEST", weapons);
    }
    
    function getNumber3(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "HEAD", weapons);
    }
    
    function getNumber4(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "WAIST", weapons);
    }

    function getNumber5(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "FOOT", weapons);
    }
    
    function getNumber6(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "HAND", weapons);
    }
    
    function getNumber7(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "NECK", weapons);
    }
    
    function getNumber8(uint256 tokenId) public view returns (string memory) {
        return pluck(tokenId, "RING", weapons);
    }
    
    
    function pluck(uint256 tokenId, string memory keyPrefix, string[] memory sourceArray) internal view returns (string memory) {
        uint256 rand = random(string(abi.encodePacked(keyPrefix, toString(tokenId))));
        string memory output = sourceArray[rand % sourceArray.length];
        output = string(abi.encodePacked(output));
        return output;
    }

    function tokenURI(uint256 tokenId) override public view returns (string memory) {
        string[17] memory parts;
        parts[0] = '<svg xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMinYMin meet" viewBox="0 0 350 350"><style>.base { fill: white; font-family: monospace; font-size: 14px; }</style><rect width="100%" height="100%" fill="#0000ff" /><text x="10" y="20" class="base">';

        parts[1] = getNumber1(tokenId);

        parts[2] = '</text><text x="10" y="40" class="base">';

        parts[3] = getNumber2(tokenId);

        parts[4] = '</text><text x="10" y="60" class="base">';

        parts[5] = getNumber3(tokenId);

        parts[6] = '</text><text x="10" y="80" class="base">';

        parts[7] = getNumber4(tokenId);

        parts[8] = '</text><text x="10" y="100" class="base">';

        parts[9] = getNumber5(tokenId);

        parts[10] = '</text><text x="10" y="120" class="base">';

        parts[11] = getNumber6(tokenId);

        parts[12] = '</text><text x="10" y="140" class="base">';

        parts[13] = getNumber7(tokenId);

        parts[14] = '</text><text x="10" y="160" class="base">';

        parts[15] = getNumber8(tokenId);

        parts[16] = '</text></svg>';

        string memory output = string(abi.encodePacked(parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6], parts[7], parts[8]));
        output = string(abi.encodePacked(output, parts[9], parts[10], parts[11], parts[12], parts[13], parts[14], parts[15], parts[16]));
        
        string memory json = Base64.encode(bytes(string(abi.encodePacked('{"name": "BlindBox #', toString(tokenId), '", "description": "BlindBox is randomized adventurer numeral system. Feel free to use Blindbox in any way you want. Fork from and inspired by Loot.", "image": "data:image/svg+xml;base64,', Base64.encode(bytes(output)), '"}'))));
        output = string(abi.encodePacked('data:application/json;base64,', json));

        return output;
    }

    function claim(uint256 tokenId) public nonReentrant payable {
        require(tokenId > 0 && tokenId < 7778, "Token ID invalid");
        // ether contribution - Blindbox
        require(msg.value > 0.03 ether);
        _safeMint(_msgSender(), tokenId);
    }
    
    function ownerClaim(uint256 tokenId) public nonReentrant onlyOwner {
        require(tokenId > 7777 && tokenId < 8001, "Token ID invalid");
        _safeMint(owner(), tokenId);
    }
    
    // withdraw funds - Blindbox
    function withdrawFunds(uint _amount, address payable _to) public onlyOwner{
        uint value = _amount;
        (bool success,  ) = _to.call{value: value}("");
        require(success, "Failed to transfer the funds, aborting.");
    }
    
    function toString(uint256 value) internal pure returns (string memory) {
    // Inspired by OraclizeAPI's implementation - MIT license
    // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }
    
    constructor() ERC721("BlindBox", "BlindBox") Ownable() {}
}
function withdrawFunds(uint _amount, address payable _to) public onlyOwner{
    uint value = _amount;
    (bool success,  ) = _to.call{value: value}("");
    require(success, "Failed to transfer the funds, aborting.");
}

// withdraw funds - Blindbox