contract Randomice is ERC721, Ownable, ReentrancyGuard {
	using Strings for uint256;

	string public baseURI;
	uint256 public cost = 0.025 ether;
    uint256 public minted;
	uint256 public maxSupply = 6969; //nice
	uint256 public maxMint = 10;
	bool public status = false;
	
    address miceAddr = 0xbad6186E92002E312078b5a1dAfd5ddf63d3f731;      //Anonymice
    address doodlesAddr = 0x8a90CAb2b38dba80c64b7734e58Ee1dB38B8992e;   //Doodles
    address babyMiceAddr = 0x15Cc16BfE6fAC624247490AA29B6D632Be549F00;  //Baby Mice

    mapping(address => bool) public mintlist;

	constructor() ERC721("RandoMice", "RMICE") {}


    //checks if address owns at least one token from either of the qualifying collections
    function isHolder(address _wallet) public view returns (bool) {
        ERC721 miceToken = ERC721(miceAddr);
        uint256 _miceBalance = miceToken.balanceOf(_wallet);
    
        ERC721 doodlesToken = ERC721(doodlesAddr);
        uint256 _doodlesBalance = doodlesToken.balanceOf(_wallet);

        ERC721 babyMiceToken = ERC721(babyMiceAddr);
        uint256 _babyMiceBalance = babyMiceToken.balanceOf(_wallet);

        return (_miceBalance + _doodlesBalance + _babyMiceBalance > 0);
  }


    //public mint
	function mint(uint256 _mintAmount) public payable nonReentrant{
		require(status, "Sale inactive" );
        require(msg.sender == tx.origin, "No contracts!");
		require(_mintAmount <= maxMint, "Too many" );
		require(minted + _mintAmount <= maxSupply, "Would excced supply" );
		require(msg.value >= cost * _mintAmount, "Not enough ETH");
   		for (uint256 i = 0; i < _mintAmount; i++) {
            minted++;
			_safeMint(msg.sender, minted);
		}
	}


    //free claim for qualifying holders
    function claim(address _wallet) external nonReentrant {
        require(status, "Sale inactive" );
        require(msg.sender == tx.origin, "No contracts!");
		require(minted + 1 <= maxSupply, "Would excced supply" );
        (bool _holder) = isHolder(_wallet);
        require(_holder, "Must own at least one qualifying NFT to claim!");
        require(mintlist[_wallet] != true, "Already claimed!");
        mintlist[_wallet] = true;
        minted++;
        _safeMint(msg.sender, minted);
     }


    //giveaways are nice
	function gift(uint[] calldata quantity, address[] calldata recipient) external onlyOwner{
		require(quantity.length == recipient.length, "Provide quantities and recipients" );
		uint totalQuantity = 0;
		for(uint i = 0; i < quantity.length; i++){
			totalQuantity += quantity[i];
		}
		require( minted + totalQuantity <= maxSupply, "Too many" );
		delete totalQuantity;
		for(uint i = 0; i < recipient.length; i++){
			for(uint j = 0; j < quantity[i]; j++){
            minted++;
			_safeMint(recipient[i], minted);
			}
		}
	}
	

    //metadata
	function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
	    require(_exists(tokenId), "Nonexistent token");
	    string memory currentBaseURI = _baseURI();
	    return bytes(currentBaseURI).length > 0	? string(abi.encodePacked(currentBaseURI, (tokenId).toString())) : "";
	}


    //setters
    function setMiceAddress(address _miceAddr) external onlyOwner {
        miceAddr = _miceAddr;
    }

    function setDoodlesAddress(address _doodlesAddr) external onlyOwner {
        doodlesAddr = _doodlesAddr;
    }

    function setBabyMiceAddress(address _babyMiceAddr) external onlyOwner {
        babyMiceAddr = _babyMiceAddr;
    }

	function setCost(uint256 _newCost) public onlyOwner {
	    cost = _newCost;
	}
	function setMaxMintAmount(uint256 _newMaxMintAmount) public onlyOwner {
	    maxMint = _newMaxMintAmount;
	}
	function setmaxSupply(uint256 _newMaxSupply) public onlyOwner {
	    maxSupply = _newMaxSupply;
	}
	function setBaseURI(string memory _newBaseURI) public onlyOwner {
	    baseURI = _newBaseURI;
    }


    //admin functions
    function _baseURI() internal view override returns (string memory) {
        return baseURI;
    }
	
	function flipSaleStatus() public onlyOwner {
	    status = !status;
	}

	function withdraw() public payable onlyOwner {
	(bool success, ) = payable(msg.sender).call{value: address(this).balance}("");
	require(success);
	}

}
function setMiceAddress(address _miceAddr) external onlyOwner {
    miceAddr = _miceAddr;
}

//setters