contract PixelMankind is ERC721Enumerable, Ownable {
    
    using Strings for uint256;

    string private baseURI = "ipfs://QmVxumYi84uFipPX8uwA29eUimCvKP1rpHyD6RhaP54jUR/"; 
    string private baseExtension = ".json";   

    uint256 public cost = 0.04 ether;
    uint256 public maxSupply = 8000;
    uint256 public maxMintAmount = 20;
    bool public paused = false;
 

    constructor() ERC721("PixelMankind", "PXM") {
        setBaseURI(baseURI);
        mintPixelHuman(1);
    }

    // public

    function mintPixelHuman(uint256 _mintAmount) public payable {
        uint256 supply = totalSupply();
        require(!paused, "the contract is paused");
        require(_mintAmount > 0 && _mintAmount <= maxMintAmount, "invalid minting amount");
        require(supply + _mintAmount <= maxSupply, "not enough tokens are available");

        if (msg.sender != owner()) {
            require(msg.value >= cost * _mintAmount, "credit not sufficient");
        }

        for (uint256 i = 1; i <= _mintAmount; i++) {

            _safeMint(msg.sender, supply + i);
            if (msg.sender != owner()) {
                payable(owner()).transfer(cost);
            }
        }

    }

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

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


    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 contractURI() public pure returns (string memory) {
        return "https://pixelmankind.io/contract-info.json";
    }

    // only owner

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

    function setBaseExtension(string memory _newBaseExtension) public onlyOwner {
        baseExtension = _newBaseExtension;
    }

    function pause(bool _newState) public onlyOwner {
        paused = _newState;
    }

    function withdraw() public payable onlyOwner {
        require(payable(msg.sender).send(address(this).balance));
    }

    // internal

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

// internal