contract xMartianNFT is ERC721Enumerable, Ownable, ERC721URIStorage {
    using Strings for uint256;

    string baseURI;
    string public baseExtension = ".json";
    uint256 public cost = 1 ether;

    uint16 public maxSupply = 10000;
    uint16 public curSupply = 10000;
    uint16 public wLSupply = 1000;

    bool public first12 = false;
    mapping(address => uint8 ) public giveAwayAllowance;
    mapping(address => uint8 ) public whiteListAllowance;
    mapping(uint256 => string) private _tokenURIs;

    constructor(
        string memory _name,
        string memory _symbol,
        string memory _initBaseURI
    ) ERC721(_name, _symbol) {
        setBaseURI(_initBaseURI);
    }
    // internal
    function _baseURI() internal view virtual override returns (string memory) {
        return baseURI;
    }
    // public
    function mint(uint8 mintQty) public payable {
        require(wLSupply == 0);
    uint256 supply = totalSupply() + mintQty;
        uint256 fCost = cost * mintQty;
        require(supply <= curSupply, "ER33");
        if (msg.sender != owner()) {
            require(msg.value >= fCost, "ER34");
        }
        curSupply = curSupply - mintQty;
        for (uint256 i; i < mintQty; i++) {
            _safeMint(msg.sender, supply - (mintQty - i));
        }
    }
    // whitelist
    function mintWhitelist(uint8 mintQty) public payable {
        uint256 supply = totalSupply() + mintQty;
        require(supply <= wLSupply);
        // change to whitelistAllowance
        if (first12 == true) {
            require(mintQty <= whiteListAllowance[msg.sender]);
            whiteListAllowance[msg.sender] = whiteListAllowance[msg.sender] - mintQty;
        }else{
            require(whiteListAllowance[msg.sender] == 0 || whiteListAllowance[msg.sender] > 0);
        }
        curSupply = curSupply - mintQty;
        for (uint256 i; i < mintQty; i++) {
            _safeMint(msg.sender, supply - (mintQty - i));
        }

    }
    // If giveaway allowance
    function mintGiveaway(uint8 mintQty) public payable {
        require(wLSupply == 0);
    uint256 supply = totalSupply() + mintQty;
        require(mintQty <= giveAwayAllowance[msg.sender]);
        giveAwayAllowance[msg.sender] = giveAwayAllowance[msg.sender] - mintQty;
        curSupply = curSupply - mintQty;
        for (uint256 i; i < mintQty; i++) {
            _safeMint(msg.sender, supply - (mintQty - i));
        }
    }

    function walletOfOwner(address _owner)
    public
    view
    returns (uint256[] memory)
    {
        uint256 ownerTokenCount = balanceOf(_owner);
        uint256[] memory tokenIds = new uint256[](ownerTokenCount);
        for (uint256 i; i < ownerTokenCount; i++) {
            tokenIds[i] = tokenOfOwnerByIndex(_owner, i);
        }
        return tokenIds;
    }
    function tokenURI(uint256 tokenId)
    public
    view
    virtual
    override(ERC721, ERC721URIStorage)
    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(),
                baseExtension
            )
        )
        : "";
    }

    function batchAddGiveAwayAllowance(
        address[] memory addr,
        uint8[] memory count
    ) external onlyOwner {

              for (uint16 i = 0; i < addr.length; i++) {
            giveAwayAllowance[addr[i]] = count[i];
        }
    }

       function batchAddWhitelistAllowance(
     address[] memory addr,
          uint8[] memory count
    ) external onlyOwner {

              for (uint16 i = 0; i < addr.length; i++) {
            whiteListAllowance[addr[i]] = count[i];
        }


    }

    //FUNCTIONS FOR OWNER
    function setMaxSupply(uint16 _newSupply) public onlyOwner {
        maxSupply = _newSupply;
    }
    function setWhiteListSupply(uint16 _newSupply) public onlyOwner {
        wLSupply = _newSupply;
    }

    function toggleFirst12() external onlyOwner {
        first12?
        first12 = false:
        first12 = true;
    }
    function setCurrentSupply(uint16 _newSupply) public onlyOwner {
        curSupply = _newSupply;
    }
    function pause() public onlyOwner {
        curSupply = 0;
    }
    function setCost(uint256 _newCost) public onlyOwner {
        cost = _newCost;
    }
    function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseURI = _newBaseURI;
    }
    function setBaseExtension(string memory _baseExtension) public onlyOwner {
        baseExtension = _baseExtension;
    }
    function redeem() public payable onlyOwner {
        uint256 sA = address(this).balance*300/1000;
        uint256 sB = address(this).balance*150/1000;
        uint256 sC = address(this).balance*100/1000;
        uint256 sD = address(this).balance*75/1000;

        Address.sendValue(payable(0xa1Dc531aA00F24665d06Ee7d3614C502c08DD964), sA);
        Address.sendValue(payable(0xd00f26915108dF339BF9B63Bd34a305052EefffB), sB);
        Address.sendValue(payable(0x1fF99B8Ba496DCa54Dcf2dC923445B889cc08800), sB);
        Address.sendValue(payable(0x95c8eE08b40107f5bd70c28c4Fd96341c8eaD9c7), sC);
        Address.sendValue(payable(0xe2bBA6BfeFCf003727627519C5193223c8fd1D76), sD);
        Address.sendValue(payable(0x203A550caB392e30B09048bBAb2F7C133f553e15), sD);
        Address.sendValue(payable(0x23FEA296223e93eA843E229b3D4aCc97e77Ac7dA), sD);
        Address.sendValue(payable(0x65371E494b8b9d473CbF7F3EdeCBfAc017C54cdB), sD);
    }
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }
    function _burn(uint256 tokenId)
    internal
    override(ERC721, ERC721URIStorage)
    {
        super._burn(tokenId);
    }
    function supportsInterface(bytes4 interfaceId)
    public
    view
    override(ERC721, ERC721Enumerable)
    returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }
    
   fallback() external payable {  
   }
    receive() external payable {
    }
}
function mintWhitelist(uint8 mintQty) public payable {
    uint256 supply = totalSupply() + mintQty;
    require(supply <= wLSupply);
    // change to whitelistAllowance
    if (first12 == true) {
        require(mintQty <= whiteListAllowance[msg.sender]);
        whiteListAllowance[msg.sender] = whiteListAllowance[msg.sender] - mintQty;
    }else{
        require(whiteListAllowance[msg.sender] == 0 || whiteListAllowance[msg.sender] > 0);
    }
    curSupply = curSupply - mintQty;
    for (uint256 i; i < mintQty; i++) {
        _safeMint(msg.sender, supply - (mintQty - i));
    }

}

// whitelist