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

    string public baseMetaUri;
    
    //General Settings
    uint16 public maxMintAmountPerTransaction = 1;
    uint16 public maxMintAmountPerWallet = 5;

    //Inventory
    uint256 public maxSupply = 77;

    //Prices
    uint256 public cost = 0.4 ether;

    //Utility
    bool public paused = true;
    
    constructor(string memory _baseUrl) ERC721A("Funky Fly Traps", "FFLYT") {
        baseMetaUri = _baseUrl;
    }

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

    // public
    function mint(uint256 _mintAmount) public payable {
        if (msg.sender != owner()) {
            uint256 ownerTokenCount = balanceOf(msg.sender);

            require(!paused, "Contract Paused");
            require(_mintAmount > 0, "Mint amount should be greater than 0");
            require(
                _mintAmount <= maxMintAmountPerTransaction,
                "Sorry you cant mint this amount at once"
            );
            require(
                totalSupply() + _mintAmount <= maxSupply,
                "Exceeds Max Supply"
            );
            require(
                (ownerTokenCount + _mintAmount) <= maxMintAmountPerWallet,
                "Sorry you cant mint more"
            );
            require(
                msg.value >= cost * _mintAmount, 
                "Insuffient funds");
        }
        _mintLoop(msg.sender, _mintAmount);
    }

    function gift(address _to, uint256 _mintAmount) public onlyOwner {
        _mintLoop(_to, _mintAmount);
    }

    function airdrop(address[] memory _airdropAddresses) public onlyOwner {
        for (uint256 i = 0; i < _airdropAddresses.length; i++) {
            address to = _airdropAddresses[i];
            _mintLoop(to, 1);
        }
    }

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

    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()))
                : "";
    }

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

     //Burn functions
    function batchBurn(uint256[] memory _BurnTokenIds) public virtual {
            for(uint256 i = 0; i < _BurnTokenIds.length; i++){
                _burn(_BurnTokenIds[i], true);
            }
    }

    function burn(uint256 _BurnTokenId) public virtual{
        _burn(_BurnTokenId, true);
    }
   
    function setmaxMintAmountPerTransaction(uint16 _amount) public onlyOwner {
        maxMintAmountPerTransaction = _amount;
    }

    function setMaxMintAmountPerWallet(uint16 _amount) public onlyOwner {
        maxMintAmountPerWallet = _amount;
    }

    function setMaxSupply(uint256 _supply) public onlyOwner {
        maxSupply = _supply;
    }

    function setBaseURI(string memory _newBaseURI) public onlyOwner {
        baseMetaUri = _newBaseURI;
    }

    function togglePause() public onlyOwner {
        paused = !paused;
    }

    function _mintLoop(address _receiver, uint256 _mintAmount) internal {
        _safeMint(_receiver, _mintAmount);
    }

    function withdraw() public payable onlyOwner {
        (bool success, ) = payable(msg.sender).call{
            value: address(this).balance
        }("");
        require(success);
    }
}
function batchBurn(uint256[] memory _BurnTokenIds) public virtual {
        for(uint256 i = 0; i < _BurnTokenIds.length; i++){
            _burn(_BurnTokenIds[i], true);
        }
}

//Burn functions