contract TakeMyMuffin is ERC721URIStorage, Pausable, Ownable {
    using SafeERC20 for IERC20;
    
    uint public priceEth = 0.5 ether;
    uint public priceTmm = 0.5 ether;

    address signer = 0x233B3d769dcBf960e3b6926aa5Bc020eb4430898;
    IERC20 public tmmToken = IERC20(0x19042021329FDdcFBea5f934FB5b2670C91F7D20);
    string public URI = "https://tmm.world/api/nfts/"; 

    constructor() ERC721("TakeMyMuffin", "TMM") {
    }

    // Admin methods

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

    function unpause() public onlyOwner {
        _unpause();
    }
    
    function setPrices(uint _priceEth, uint _priceTmm) public onlyOwner {
        priceEth = _priceEth;
        priceTmm = _priceTmm;
    }
    
    function setURI(string memory _URI) public onlyOwner {
        URI = _URI;
    } 
    
    function setSigner(address _signerAddress) public onlyOwner {
        signer = _signerAddress;
    }
    
    function setTmmAddress(IERC20 _tmmAddress) public onlyOwner {
        tmmToken = _tmmAddress;
    }
      
    function withdrawTokens(uint256 _amount, IERC20 _tokenAddress) public onlyOwner {
        _tokenAddress.safeTransfer(msg.sender, _amount);
    }
    
    // Public methods
    
    function hash(uint _tokenId, address _address, string memory _tokenUri) public pure returns (bytes32) {
        return keccak256(abi.encode(
            _tokenId,
            _address,
            keccak256(bytes(_tokenUri))
        ));
    }
    
    function buyNft(uint256 tokenId, string memory tokenUri, uint8 v, bytes32 r, bytes32 s) public whenNotPaused payable {
        require(_verify(tokenId, tokenUri, v, r, s), "ECDSA: invalid signature");

        uint256 allowance = tmmToken.allowance(msg.sender, address(this));
        
        require(allowance >= priceTmm, "Check the token allowance");
        require(msg.value >= priceEth, "Not enough funds sent to purchase");
        
        tmmToken.safeTransferFrom(msg.sender, address(this), priceTmm);
        
        payable(owner()).transfer(msg.value);
        
        _safeMint(msg.sender, tokenId, tokenUri);
    }
    
    // Internal methods
    
    function _baseURI() internal view override returns (string memory) {
        return URI;
    }
    
    function _verify(uint _tokenId,  string memory _tokenUri, uint8 v, bytes32 r, bytes32 s)  internal view returns (bool response) {
        bytes32 digest = hash(_tokenId, msg.sender, _tokenUri);
        return signer == ecrecover(digest, v, r, s);
    }

    function _safeMint(address to, uint256 tokenId, string memory uri) internal {
        super._safeMint(to, tokenId);
        _setTokenURI(tokenId, uri);
    }

    function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal whenNotPaused override {
        super._beforeTokenTransfer(from, to, tokenId);
    }    
   
}
function hash(uint _tokenId, address _address, string memory _tokenUri) public pure returns (bytes32) {
    return keccak256(abi.encode(
        _tokenId,
        _address,
        keccak256(bytes(_tokenUri))
    ));
}

// Public methods