contract TheIkigai5 is ERC721Enumerable, Ownable {
    using Counters for Counters.Counter;
    Counters.Counter private _tokenId;

    uint256 public constant MAX_TI5 = 5000;
    uint256 public price = 50000000000000000; //0.05 ETH
    uint256 public presalePrice = 50000000000000000; //0.05 ETH
    string baseTokenURI;
    bool public saleOpen = false;
    bool public presaleOpen = false;

    mapping(address => uint256) public publicSaleNftCount;

    event TheIkigai5Minted(uint256 totalMinted);

    constructor(string memory baseURI) ERC721("The Ikigai 5", "TI5") {
        setBaseURI(baseURI);
    }

    //Get token Ids of all tokens owned by _owner
    function walletOfOwner(address _owner)
        external
        view
        returns (uint256[] memory)
    {
        uint256 tokenCount = balanceOf(_owner);

        uint256[] memory tokensId = new uint256[](tokenCount);
        for (uint256 i = 0; i < tokenCount; i++) {
            tokensId[i] = tokenOfOwnerByIndex(_owner, i);
        }

        return tokensId;
    }

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

    function setPrice(uint256 _newPrice) external onlyOwner {
        price = _newPrice;
    }

    function setPresalePrice(uint256 _newPresalePrice) external onlyOwner {
        presalePrice = _newPresalePrice;
    }

    //Close sale if open, open sale if closed
    function flipSaleState() external onlyOwner {
        saleOpen = !saleOpen;
    }

    function flipPresaleState() external onlyOwner {
        presaleOpen = !presaleOpen;
    }

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

    function airdrop(address[] calldata _recipients) external onlyOwner {
        require(
            totalSupply() + _recipients.length <= MAX_TI5,
            "Airdrop will exceed maximum supply of The Ikigai 5"
        );
        for (uint256 i = 0; i < _recipients.length; i++) {
            require(_recipients[i] != address(0), "Airdrop to Null address");
            _mint(_recipients[i]);
        }
    }

    //mint TheIkigai5
    function mintTheIkigai5(uint256 _count) external payable {
        require(
            totalSupply() + _count <= MAX_TI5,
            "Exceeds maximum supply of The Ikigai 5"
        );
        require(
            _count > 0,
            "Minimum 1 The Ikigai 5 has to be minted per transaction"
        );

        address _to = msg.sender;
        if (_to != owner()) {
            require(saleOpen || presaleOpen, "Minting is not live yet");
            require(
                _count <= 10,
                "Maximum 10 The Ikigai 5 can be minted per transaction"
            );
            require(
                10 >= publicSaleNftCount[_to] + _count,
                "Maximum 10 The Ikigai 5 can be minted per address"
            );
            if (saleOpen) {
                require(
                    msg.value >= price * _count,
                    "Ether sent with this transaction is not correct"
                );
            } else {
                require(
                    totalSupply() + _count <= 1000,
                    "Exceeds maximum supply of The Ikigai 5"
                );
                require(
                    msg.value >= presalePrice * _count,
                    "Ether sent with this transaction is not correct"
                );
            }
        }

        publicSaleNftCount[_to] += _count;
        for (uint256 i = 0; i < _count; i++) {
            _mint(_to);
        }
    }

    function _mint(address _to) private {
        _tokenId.increment();
        uint256 tokenId = _tokenId.current();
        _safeMint(_to, tokenId);
        emit TheIkigai5Minted(tokenId);
    }

    function _baseURI() internal view virtual override returns (string memory) {
        return baseTokenURI;
    }
}
function walletOfOwner(address _owner)
    external
    view
    returns (uint256[] memory)
{
    uint256 tokenCount = balanceOf(_owner);

    uint256[] memory tokensId = new uint256[](tokenCount);
    for (uint256 i = 0; i < tokenCount; i++) {
        tokensId[i] = tokenOfOwnerByIndex(_owner, i);
    }

    return tokensId;
}

//Get token Ids of all tokens owned by _owner