contract BabyCoterie is ERC721A, Ownable {
    
    using SafeMath for uint256;

    string public BABY_PROVENANCE = ""; // IPFS URL WILL BE ADDED WHEN BABIES ARE ALL SOLD OUT
    
    string public LICENSE_TEXT = ""; // IT IS WHAT IT SAYS
    
    bool licenseLocked = false; // TEAM CAN'T EDIT THE LICENSE AFTER THIS GETS TRUE

    uint256 public babyPrice = 20000000000000000; // 0.02 ETH

    uint public constant maxBabyPurchase = 20;

    uint public freeBabiesClaimed = 0;

    uint256 public constant MAX_BABIES = 10000;

    bool public saleIsActive = false;

    bool public whitelistSaleIsActive = false;
    
    bool public uriIsFrozen = false;

    bool public bypassMintLimit = false;

    address public constant ADDRESS_DEV = 0x7DF76FDEedE91d3cB80e4a86158dD9f6D206c98E;

    address public constant ADDRESS_ART = 0xE1F04a8e7609482B0A96a4636bb2d0211e3A4fF9;
    
    address public ADDRESS_TEAM = 0x0709C9feEeA75ad21153808fB0094a3aE2F44e94;

    mapping(address => bool) blacklistedAddresses;
    
    
    event licenseisLocked(string _licenseText);

    constructor() ERC721A("Baby Coterie", "BABY", 20, 10000) { }
    
    function withdraw() public {
        uint balance = address(this).balance;
        uint dev_cut = balance/20;
        uint art_cut = balance/10;
        payable(ADDRESS_DEV).transfer(dev_cut);
        payable(ADDRESS_ART).transfer(art_cut);
        payable(ADDRESS_TEAM).transfer(address(this).balance);
    }


    function setProvenanceHash(string memory provenanceHash) public onlyOwner {
        BABY_PROVENANCE = provenanceHash;
    }

    function setBabyPrice(uint256 _babyPrice) public onlyOwner {
        babyPrice = _babyPrice;
    }

    string private _baseTokenURI;

    function _baseURI() internal view virtual override returns (string memory) {
    return _baseTokenURI;
  }

    function setBaseURI(string calldata baseURI) external onlyOwner {
      require(uriIsFrozen == false, "The BaseURI has been frozen and can not be changed.");
      _baseTokenURI = baseURI;
  }
    
    function freezeBaseURI() public onlyOwner {
        require(uriIsFrozen == false, "The BaseURI has already been frozen.");
        uriIsFrozen = true;
    }


    function flipSaleState() public onlyOwner {
        saleIsActive = !saleIsActive;
    }

    function flipBypassMintLimit() public onlyOwner {
        bypassMintLimit = !bypassMintLimit;
    }

    function flipWhitelistSaleState() public onlyOwner {
        whitelistSaleIsActive = !whitelistSaleIsActive;
    }

    function setTeamAddress(address teamAddress) public onlyOwner {
        ADDRESS_TEAM = teamAddress;
    }
    
    
    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;
        }
    }
    
    // Returns the license for tokens
    function tokenLicense(uint _id) public view returns(string memory) {
        require(_id < totalSupply(), "CHOOSE A BABY WITHIN RANGE");
        return LICENSE_TEXT;
    }
    
    // Locks the license to prevent further changes 
    function lockLicense() public onlyOwner {
        licenseLocked =  true;
        emit licenseisLocked(LICENSE_TEXT);
    }
    
    // Change the license
    function changeLicense(string memory _license) public onlyOwner {
        require(licenseLocked == false, "License already locked");
        LICENSE_TEXT = _license;
    }
    

    function publicMintBaby(uint numberOfTokens) public payable {
        require(saleIsActive, "Sale must be active to mint a Baby");
        require(numberOfTokens > 0 && numberOfTokens <= maxBabyPurchase, "Can only mint 20 tokens at a time");

        //Reserved for OG whitelist
        require(totalSupply().add(numberOfTokens) <= MAX_BABIES-300 || bypassMintLimit == true, "Purchase would exceed max supply of Babies, 300 are reserved for the team");
        
        require(totalSupply().add(numberOfTokens) <= MAX_BABIES, "Purchase would exceed max supply of Babies" );
        require(msg.value >= babyPrice.mul(numberOfTokens), "Ether value sent is not correct");
        _safeMint(msg.sender, numberOfTokens);
    }

      function ownerMintBaby(address _receiver, uint numberOfTokens) public onlyOwner {
        require(totalSupply().add(numberOfTokens) <= MAX_BABIES, "Minting would exceed max supply of Babies" );
        _safeMint(_receiver, numberOfTokens);
    }
    
    function whitelistMintBaby() public {
        require(blacklistedAddresses[msg.sender] == false, "You have already minted your free baby");
        require(whitelistSaleIsActive, "Sale must be active to mint a Baby");
        require(totalSupply().add(1) <= MAX_BABIES, "Purchase would exceed max supply of Babies");
        require(freeBabiesClaimed < 750, "All 750 free babies have already been minted");
        _safeMint(msg.sender,1);
        blacklistedAddresses[msg.sender] = true;
        freeBabiesClaimed++;
    }

    
    

    
}
function changeLicense(string memory _license) public onlyOwner {
    require(licenseLocked == false, "License already locked");
    LICENSE_TEXT = _license;
}

// Change the license