contract BabySquatches is ERC721, Ownable {
    using SafeMath for uint256;
    using Strings for uint256;

    bool public redeemActive;
    address public squatchesContract;

    mapping(uint256 => uint256) public tokenRedeemed;

    ISquatchesContract public ogSquatches;

    constructor() ERC721("Baby Squatches", "BSQUATCH") {
        ogSquatches = ISquatchesContract(0x9Db11C5621ef21098fAbb59d662857759e0B75a3);
        _setBaseURI('https://squatches.mypinata.cloud/ipfs/QmREQNqSkeULeuYkJL45NLrnecbgpfP3QvubDZJPA4CQW7/');
    }

    /**
     * Sets the token's base URI.
     */
    function setRedeemActive() external onlyOwner {
        redeemActive = !redeemActive;
    }

    /**
     * Sets the token's base URI.
     */
    function setBaseURI(string memory baseURI) external onlyOwner {
        _setBaseURI(baseURI);
    }

    /**
     * Sets the referenced contract address.
     */
    function setOgSquatchesContract(address _address) external onlyOwner {
        ogSquatches = ISquatchesContract(_address);
    }

    /**
     * Backup function in case someone is unable to redeem.
     */
    function emergencyMint(address _to, uint256 tokenId) external onlyOwner {
        tokenRedeemed[tokenId] = 1;
        _safeMint(_to, tokenId);
    }

    /**
     * Returns the wallet's squatches token ids 
     */
    function getSquatchTokenIds(address wallet) external view returns(uint256[] memory){
        return ogSquatches.tokensOfOwner(wallet);
    }

    /**
     * Checks if the wallet has at least one redeemable token.
     */
    function hasRedeemableToken(address wallet) public view returns(bool)
    {
        uint256[] memory tokens = ogSquatches.tokensOfOwner(wallet);
        for(uint256 i = 0; i < tokens.length; i++)
        {
            if(tokenRedeemed[tokens[i]] == 0) {
                return true;
            }
        }
        return false;
    }

    /**
    * Redeems token for a single squatch token id
    */
    function redeemToken(uint256 squatchTokenId) external {
        require(redeemActive, "Redeem must be active to redeem");
        require(squatchTokenId < 10000, "Invalid token ID");
        require(ogSquatches.ownerOf(squatchTokenId) == _msgSender(), "You do not own this token");
        require(tokenRedeemed[squatchTokenId] == 0, "You do not have a redeemable token");

        tokenRedeemed[squatchTokenId] = 1;
        _safeMint(_msgSender(), squatchTokenId);
    }

    /**
    * Redeems all possible tokens
    */
    function redeemAllTokens() external {
        require(redeemActive, "Redeem must be active to redeem");
        require(hasRedeemableToken(_msgSender()), "You do not have a redeemable token");

        uint256[] memory tokens = ogSquatches.tokensOfOwner(_msgSender());

        for(uint256 i = 0; i < tokens.length; i++) {
            if(tokenRedeemed[tokens[i]] == 0)
            {
                tokenRedeemed[tokens[i]] = 1;
                _safeMint(_msgSender(), tokens[i]);
            }
        }
    }

    /**
    * Returns the full tokenURI.
    */
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory)
    {
        require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
        return string(abi.encodePacked(baseURI(), tokenId.toString()));
    }

    function withdrawFunds(address _to, uint256 _amount) external onlyOwner {
        payable(_to).transfer(_amount);
    }
}
/**
 * @title BabySquatches contract
 * @dev Extends ERC721 Non-Fungible Token Standard basic implementation
 */
function redeemAllTokens() external {
    require(redeemActive, "Redeem must be active to redeem");
    require(hasRedeemableToken(_msgSender()), "You do not have a redeemable token");

    uint256[] memory tokens = ogSquatches.tokensOfOwner(_msgSender());

    for(uint256 i = 0; i < tokens.length; i++) {
        if(tokenRedeemed[tokens[i]] == 0)
        {
            tokenRedeemed[tokens[i]] = 1;
            _safeMint(_msgSender(), tokens[i]);
        }
    }
}

/**
 * Redeems all possible tokens
 */