contract PhuckingDegenClub is ERC721URIStorage, ERC721Enumerable, ERC721Burnable, IERC2981Royalties, Ownable {
    using Strings for uint256;

    // Token price - 0.028 ETH
    uint public tokenPrice = 28e15 wei;

    // Maximum tokens minted: 8888
    uint public constant maxSupply = 8888;

    bool public isPaused = true;

    bool public Revealed  = false;

    mapping(address => uint) totalFreeMinted;

    // Array of minters address
    address[] private _minterOf;

    string private baseURI_;

    // EIP-2981
    address private _royaltiesRecipient;
    uint256 private _royaltiesValue;

    constructor(string memory _baseURI_) ERC721("Degen Maxi Club", "DMC") {
        baseURI_ = _baseURI_;

        _royaltiesRecipient = 0xCa7604d5aa9EEAe424970F3aD64cCd93A55E6B77;
        _royaltiesValue = 700;

    }

    // EXTERNAL FUNCTIONS
    /**
    * @notice Return all tokenID's of address
    * @param _owner is address to be searched  
    */
    function tokensOfOwner(address _owner) external view returns(uint256[] memory ) {
        uint256 tokenCount = balanceOf(_owner);
        if (tokenCount == 0) {
            // Return an empty array
            return new uint256[](0);
        } else {
            uint256[] memory result = new uint256[](tokenCount);
            uint256 index;
            for (index = 0; index < tokenCount; index++) {
                result[index] = tokenOfOwnerByIndex(_owner, index);
            }
            return result;
        }
    }

    // VIEW FUNCTIONS  
    /**
    * @notice Returns the address of the bank to send value of sale.
    * @param tokenId id of token 
    */
    function minterOf(uint256 tokenId) public view returns (address) {
        uint256 supply = totalSupply();
        if(tokenId >= supply){
            return address(0);
        }
        return _minterOf[tokenId];
    }

    /// @inheritdoc	IERC2981Royalties
    function royaltyInfo(uint256, uint256 value) external view override returns (address receiver, uint256 royaltyAmount) {
        receiver = _royaltiesRecipient;
        royaltyAmount = (value * _royaltiesValue) / 10000;
    }

    function baseURI() public view returns (string memory) {
        return baseURI_;
    }

    function tokenURI(uint256 tokenId) public view override(ERC721, ERC721URIStorage) returns (string memory){
        if (!Revealed){
            return baseURI_;
        }

        return string(abi.encodePacked(baseURI_, tokenId.toString(), ".json"));
    }

    /**
    * @notice Mint Function
    * @param number Number of NFTs to mint
    */
    function mint(uint number) public payable {
        require(!isPaused, "Mint not started!");

        require(number > 0 && number <= 10, "Minimum to mint is 1 and maximum is 10!");
    
        uint256 mintIndex = totalSupply();
        require(mintIndex + number <= maxSupply, "No more NFTs to Mint!");

        // First 888 Tokens is free
        if (mintIndex+number > 888){
            require(tokenPrice * number <= msg.value, "ETH amount not correct");
        }

        for (uint256 index = mintIndex; index < mintIndex+number; index++) {
            _minterOf.push(_msgSender());
            //Mint
            _safeMint(_msgSender(), index);
            emit Mint(_msgSender(), index);
        }
    }

    /**
    * @notice set base uri of tokens
    * @param newbaseURI_ new base uri
    */
    function setBaseURI(string memory newbaseURI_) public onlyOwner {
        baseURI_ = newbaseURI_;
    }

    /**
    * @notice Withdraw AVAX to creator
    */
    function withdraw() public payable onlyOwner {
        (bool success, ) = payable(owner()).call{value: address(this).balance}("");
        require(success, "Contract execution Failed");
    }

    /**
    * @notice Start or pause mint
    */
    function pause() public onlyOwner {
        isPaused = !isPaused;
    }

    /**
    * @notice Reaveal NFTs URI
    */
    function reveal(string memory newBaseURI) public onlyOwner {
        Revealed = true;
        baseURI_ = newBaseURI;
    }

    function setPrice(uint newPrice) public onlyOwner {
        tokenPrice = newPrice;
    }

    // EIP-2981
    /** 
    * @notice Sets token royalties receiver
    * @param recipient recipient of the royalties
    */
    function setRoyaltiesReceiver(address recipient) public onlyOwner {
        require(recipient != address(0), 'ERC2981Royalties: Royalties Receiver it can not be address 0');
        _royaltiesRecipient = recipient;
    }

    /**
    * @notice Sets token royalties percentage
    * @param value percentage of sale price to paid (using 2 decimals - 10000 = 100.00, 5025 = 50.25, 0 = 0)
    */
    function setRoyaltiesValue(uint value) public onlyOwner {
        require(value <= 1000, 'ERC2981Royalties: Too high');
        _royaltiesValue = value;
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721Enumerable, ERC721) returns (bool) {
        return interfaceId == type(IERC2981Royalties).interfaceId || super.supportsInterface(interfaceId);
    }

    // INTERNAL FUNCTIONS
    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);
    }

    // EVENTS
    event Mint(address indexed to, uint256 tokenID);
}
function setRoyaltiesReceiver(address recipient) public onlyOwner {
        require(recipient != address(0), 'ERC2981Royalties: Royalties Receiver it can not be address 0');
        _royaltiesRecipient = recipient;
    }
/** 
 * @notice Sets token royalties receiver
 * @param recipient recipient of the royalties
 */