contract GirlDrop is Ownable, ERC721A, ReentrancyGuard, ERC2981 {
  uint256 public collectionSize;
  uint256 public currentPrice;
  uint256 public dropEnd;
  uint256 public maxBatchSize;
  uint256 public amountForPromotion;
  address public daoLocker;
  address proxyRegistryAddress;


  constructor(
    uint256 collectionSize_,
    uint256 currentPrice_,
    uint256 dropEnd_,
    uint256 maxBatchSize_,
    uint256 amountForPromotion_,
    string memory baseURI_,
    address proxyRegistryAddress_
  ) ERC721A("GirlDrop", "GIRLDROP") {
    collectionSize = collectionSize_;
    currentPrice = currentPrice_;
    dropEnd = dropEnd_;
    maxBatchSize = maxBatchSize_;
    amountForPromotion = amountForPromotion_;
    _baseTokenURI = baseURI_;
    
    proxyRegistryAddress = proxyRegistryAddress_;
    _setDefaultRoyalty(owner(), 500);
    daoLocker = owner();
  }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, ERC2981) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

  function setDefaultRoyalty(address recipient, uint96 fraction) public onlyOwner(){
        _setDefaultRoyalty(recipient, fraction);
    }

  function startNextDrop(    
    uint256 dropSize_,
    uint256 currentPrice_,
    uint256 dropEnd_,
    uint256 maxBatchSize_,
    uint256 amountForPromotion_) public onlyOwner() {
      require(maxBatchSize_ >= 1, "Max batch size is too small");
      collectionSize += dropSize_;
      currentPrice = currentPrice_;
      dropEnd = dropEnd_;
      maxBatchSize = maxBatchSize_;
      amountForPromotion = amountForPromotion_;
  }

  function closeDrop() public onlyOwner() {
      require(totalSupply() < collectionSize, "Drop is fully sold");
      uint256 amountToLock = collectionSize - totalSupply();
      _safeMint(daoLocker, amountToLock);
  }

  function refundIfOver(uint256 price) private {
    require(msg.value >= price, "Need to send more ETH.");
    if (msg.value > price) {
      payable(msg.sender).transfer(msg.value - price);
    }
  }

  modifier callerIsUser() {
    require(tx.origin == msg.sender, "The caller is another contract");
    _;
  }

  function mintNFT(uint256 numberOfNfts) public payable callerIsUser {
    uint256 available = collectionSize - amountForPromotion;
    require(totalSupply() < available, "Sold Out");
    require(block.timestamp < dropEnd, "Drop is finished");
    require(numberOfNfts <= maxBatchSize, "Exceeds max tokens per purchase");
    require(totalSupply() + numberOfNfts <= available, "Exceeds MAX_NFT_SUPPLY");

    uint256 totalCost = currentPrice * numberOfNfts;
    _safeMint(msg.sender, numberOfNfts);
    refundIfOver(totalCost);
  }

      // // metadata URI
  string private _baseTokenURI;

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

  function setBaseURI(string calldata baseURI) external onlyOwner {
    _baseTokenURI = baseURI;
  }

  function withdrawMoney() external onlyOwner nonReentrant {
    (bool success, ) = msg.sender.call{value: address(this).balance}("");
    require(success, "Transfer failed.");
  }

  function numberMinted(address owner) public view returns (uint256) {
    return _numberMinted(owner);
  }

  function getOwnershipData(uint256 tokenId)
    external
    view
    returns (TokenOwnership memory)
  {
    return ownershipOf(tokenId);
  }

//opensea gas saving
  function isApprovedForAll(address owner, address operator)
      override
      public
      view
      returns (bool)
  {
      // Whitelist OpenSea proxy contract for easy trading.
      ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
      if (address(proxyRegistry.proxies(owner)) == operator) {
          return true;
      }

      return super.isApprovedForAll(owner, operator);
  }

}
function isApprovedForAll(address owner, address operator)
    override
    public
    view
    returns (bool)
{
    // Whitelist OpenSea proxy contract for easy trading.
    ProxyRegistry proxyRegistry = ProxyRegistry(proxyRegistryAddress);
    if (address(proxyRegistry.proxies(owner)) == operator) {
        return true;
    }

    return super.isApprovedForAll(owner, operator);
}

//opensea gas saving