contract KingEerosKnights is ERC721A, Ownable {
    using Strings for uint256;

    uint256 public constant MAX_GEMS = 9999;
    uint256 public constant MAX_GEMS_MINTED = 10;
    uint256 private knightsCount = 0;
    bool public isKing = false;
    bool public isQueen = false;
    string public constant BASE_TOKEN_URI = "ipfs://QmeG5bEemxUxzNJkQAANabDAfGJ5xrCQdnMJSfhJVPaxbx/";
    string public constant GEM_CLARITY = "GEM CLARITY";
    string public constant GEM_CUT = "GEM CUT";

    constructor() ERC721A("King Eeros Knights", "CROWN") {} 

     /**
     * @dev See {ERC721-_beforeTokenTranfser}.
     */
     function _beforeTokenTransfers(
        address from,
        address to,
        uint256 startTokenId,
        uint256 quantity
    ) internal virtual override {
        require(from == address(0) || totalSupply() >= MAX_GEMS, "not permitted until all gems are minted");
        super._beforeTokenTransfers(from, to, startTokenId, quantity);
    }

    /**
     * @dev Mint your gems for free (eth gas fees only).
     * @param _numberOfGems The number of gems you want to mint. Max 10 per wallet.
     */
    function mintGems(uint256 _numberOfGems) public {
        uint256 currentTotal = totalSupply();
        require(_numberOfGems > 0, "wtf");
        require(currentTotal + _numberOfGems <= MAX_GEMS, "fren, gems are minted");
        require(balanceOf(_msgSender()) + _numberOfGems <= MAX_GEMS_MINTED, "greedy");

        _safeMint(msg.sender, _numberOfGems);
    }

    function getGemId(uint256 _tokenId) internal pure returns (uint256) {
        uint256 rarity = uint256(keccak256(abi.encodePacked("GEM", Strings.toString(_tokenId)))) % 101;
        uint256 gemId = 0;
        if (rarity >= 15) { gemId = 1; }
        if (rarity >= 25) { gemId = 2; }
        if (rarity >= 50) { gemId = 3; }
        if (rarity >= 75) { gemId = 4; }
        if (rarity >= 90) { gemId = 5; }
        if (rarity >= 96) { gemId = 6; }
        if (rarity >= 99) { gemId = 8; }
        if (rarity == 69) { gemId = 7; }
        return gemId;
    }

    function getGrade(uint256 _tokenId, string memory _gradeType) internal pure returns (uint256) {
        uint256 rarity = uint256(keccak256(abi.encodePacked(_gradeType, Strings.toString(_tokenId)))) % 101;
        uint256 grade = 0;
        if (rarity >= 5) { grade = 1; }
        if (rarity >= 25) { grade = 2; }
        if (rarity >= 90) { grade = 3; }
        if (rarity == 100) { grade = 4; }
        return grade;
    }

    function getKnighted(uint256[] memory knightKeys) public {
        require(totalSupply() >= MAX_GEMS, "not permitted until all gems are minted");
        require(knightsCount < 9, "Knights are knighted");
        require(knightKeys[10] == uint256(keccak256(abi.encodePacked(msg.sender))) % 69, "oooooh, try again ser");
        for (uint256 i = 0; i < 9; i++) {
            uint256 _tokenId = knightKeys[i];
            require(ownerOf(_tokenId) == msg.sender);
            require(getGemId(_tokenId) == knightsCount);
            transferFrom(msg.sender, 0x000000000000000000000000000000000000dEaD, _tokenId);
        } 
        uint256 _gripTokenId = knightKeys[9];
        require(ownerOf(_gripTokenId) == msg.sender);
        require(getGemId(_gripTokenId) == 6);

        // mint sword
        _safeMint(msg.sender, 1);
        knightsCount = knightsCount + 1;
    }
    
    function claimThrone(uint256[] memory crownKeys) public {
        require(!isKing || !isQueen);
        require(knightsCount >= 9, "Knights are not knighted");
        require(crownKeys[20] == uint256(keccak256(abi.encodePacked(msg.sender))) % 69, "oooooh, try again ser");
        uint256 minGems = isQueen ? 100 : 50;
        require(balanceOf(_msgSender()) >= minGems, "needs more gems to claim the crown"); 

        for (uint256 i = 0; i < 5; i++) {
            uint256 _tokenId = crownKeys[i];
            require(ownerOf(_tokenId) == msg.sender);
            require(getGrade(_tokenId, GEM_CLARITY) == i);
        }

        for (uint256 i = 0; i < 5; i++) {
            uint256 _tokenId = crownKeys[i + 5];
            require(ownerOf(_tokenId) == msg.sender);
            require(getGrade(_tokenId, GEM_CUT) == i);
        }

        for (uint256 i = 0; i < 9; i++) {
            uint256 _tokenId = crownKeys[i + 10];
            require(ownerOf(_tokenId) == msg.sender);
            require(getGemId(_tokenId) == i);
            transferFrom(msg.sender, 0x000000000000000000000000000000000000dEaD, _tokenId);
        } 

        // mint crown
        _safeMint(msg.sender, 1);

        if (isQueen) {
            isKing = true;
        }
        isQueen = true;
    }

    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        uint256 gemId = getGemId(tokenId);
        uint256 gemClarity = getGrade(tokenId, GEM_CLARITY);
        uint256 gemCut = getGrade(tokenId, GEM_CUT);
        uint256 path = gemId * 100 + gemClarity * 10 + gemCut;
        
        if (tokenId >= MAX_GEMS) {
            uint256 uniqueCount = tokenId - MAX_GEMS;
            path = uniqueCount + 1000;
            if (uniqueCount == 9) {
                path = 1420;
            }
            if (uniqueCount == 10) {
                path = 1069;
            }
        }
        if (totalSupply() < MAX_GEMS) {
            path = 999;
        }
        return string(abi.encodePacked(BASE_TOKEN_URI, Strings.toString(path)));
    }
}
function _beforeTokenTransfers(
   address from,
   address to,
   uint256 startTokenId,
   uint256 quantity
 internal virtual override {
   require(from == address(0) || totalSupply() >= MAX_GEMS, "not permitted until all gems are minted");
   super._beforeTokenTransfers(from, to, startTokenId, quantity);


/**
 * @dev See {ERC721-_beforeTokenTranfser}.
 */