contract cyberpunk_mfers is ERC721A, Ownable {
  using Strings for uint256;

  uint256 public cost = 0.02019 ether;
  uint256 public maxSupply = 10728;
  uint256 public maxMintAmountPerTx = 10;
  uint256 public freeMaxMintPerWallet = 5;

  uint256 FREE_MINT_MAX = 1049;

  mapping(address => uint256) public freeWallets;

  string _baseTokenURI;

  constructor(
    string memory _name,
    string memory _symbol,
    string memory baseURI
  ) ERC721A(_name, _symbol) {
      _baseTokenURI = baseURI;
  }

  modifier mfKnowsWhatTheyDoing(uint256 _mintAmount) {
    require(totalSupply() + _mintAmount <= maxSupply, "Max supply exceeded, MF!");
    require(_mintAmount > 0 && _mintAmount <= maxMintAmountPerTx, "Invalid mint amount, mf. Try something below 11.");
    _;
  }

  function mintForFree(uint256 _mintAmount) public mfKnowsWhatTheyDoing(_mintAmount) {
    require(isFreeMint(), "Too late for free mint, mf.");
    require(freeWallets[msg.sender] + _mintAmount <= freeMaxMintPerWallet, "You've already got enough for free, mf!");
    freeWallets[msg.sender] = freeWallets[msg.sender] + _mintAmount;
    _safeMint(msg.sender, _mintAmount);
  }

  function mintForMoney(uint256 _mintAmount)
    external
    payable
    mfKnowsWhatTheyDoing(_mintAmount)
  {
    require(msg.value >= cost * _mintAmount, "Damn, send more eth, mf.");
    _safeMint(msg.sender, _mintAmount);

    // Refund the mf if they sent more money. lol.
    if (msg.value > cost * _mintAmount) {
        payable(msg.sender).transfer(msg.value - (cost * _mintAmount));
    }
  }

  function isFreeMint() internal view returns (bool) {
    return totalSupply() <= FREE_MINT_MAX;
  }
  
  function mintForAddress(uint256 _mintAmount, address _receiver) public onlyOwner {
    _safeMint(_receiver, _mintAmount);
  }

  function setCost(uint256 _cost) public onlyOwner {
    cost = _cost;
  }

  function setMaxMintAmountPerTx(uint256 _maxMintAmountPerTx) public onlyOwner {
    maxMintAmountPerTx = _maxMintAmountPerTx;
  }

  function setMaxFreeMint(uint256 _max) public onlyOwner {
    FREE_MINT_MAX = _max;
  }

  function withdraw() public onlyOwner {
    uint256 bal = address(this).balance;
    // Ukraine War Crisis Relief - check twitter.com/Ukraine for their official tweet on their address. And fuck Putin.
    (bool ukraine,) = payable(0x165CD37b4C644C2921454429E7F9358d18A45e14).call{value: bal * 15 / 100}("");
    require(ukraine);
    // Sartoshi address - The @sartoshi_nft - sartoshi.eth
    (bool sartoshi,) = payable(0xeD98464BDA3cE53a95B50f897556bEDE4316361c).call{value: bal * 10 / 100}("");
    require(sartoshi);
    // Creator
    (bool creator,) = payable(0xC62F73f7dcfF8Ac5Fb2287f26566a1533514C786).call{value: bal * 35 / 100}("");
    require(creator);
    // Deployer
    (bool deployer,) = payable(0xa3F61d1eEB1c5a1379a4DCf1890f71Ca835b9454).call{value: bal * 34 / 100}("");
    require(deployer);
    // Hashlips
    (bool hashlips,) = payable(0x943590A42C27D08e3744202c4Ae5eD55c2dE240D).call{value: bal * 5 / 100}("");
    require(hashlips);
    // Contract Dev
    (bool developer,) = payable(0x446B7f1EC4749fddAfC50CcaA0c8f82d4665FB61).call{value: bal * 1 / 100}("");
    require(developer);
    if (address(this).balance > 0) { // Fail-safe. Just in case my math skills have outskilled me.
      (bool os, ) = payable(owner()).call{value: address(this).balance}("");
      require(os);
    }
  }

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

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

  function tokenURI(uint256 _tokenId)
    public
    view
    virtual
    override
    returns (string memory)
  {
    require(
      _exists(_tokenId),
      "ERC721Metadata: URI query for nonexistent token"
    );

    string memory currentBaseURI = _baseURI();
    return bytes(currentBaseURI).length > 0
        ? string(abi.encodePacked(currentBaseURI, _tokenId.toString(), ".json"))
        : "";
  }

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