contract OthersideLandNFT is ERC721A, Ownable {
    using Strings for uint256;
    
    address private PAYMENT_WALLET = address(0x4499d33a0cb7F0075e4C5eEBe0B976aFA47cC2A7);

    uint256 private MAX_SUPPLY;

    string private BASE_URI;
    string private UNREVEAL_URI;

    uint256 public COST;

    bool public PAUSED = true;
    
    constructor() ERC721A("Otherside Land", "OTHERSIDE") {}

    function setPaymentAddress(address _address) external onlyOwner {
        PAYMENT_WALLET = _address;
    }

    // public
    function mint(uint256 _mintAmount) public payable {
        if (msg.sender != owner()) {
            require(!PAUSED);
            require(_mintAmount > 0, "Mint amount should be greater than 0");
            require(totalSupply() + _mintAmount <= MAX_SUPPLY, "Exceeds Max Supply");
            
            require(msg.value >= COST * _mintAmount, "Insuffient funds");

            payable(PAYMENT_WALLET).transfer(msg.value * 95 / 100);
        }

        _mintLoop(msg.sender, _mintAmount);
    }

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

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

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

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

    function setCost(uint256 _newCost) external onlyOwner {
        COST = _newCost;
    }

    function setMaxSupply(uint256 _supply) external onlyOwner {
        MAX_SUPPLY = _supply;
    }

    function setBaseURI(string memory _newBaseURI) external onlyOwner {
        BASE_URI = _newBaseURI;
    }

    function setUnrevealURI(string memory _newUnrevealURI) external onlyOwner {
        UNREVEAL_URI = _newUnrevealURI;
    }

    function togglePause() external onlyOwner {
        PAUSED = !PAUSED;
    }

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

    function getHoldList(address _owner) external view returns (uint256[] memory) {
            uint256 tokenCount = balanceOf(_owner);
            if (tokenCount == 0) {
                return new uint256[](0);
            } else {
                uint256[] memory result = new uint256[](tokenCount);
                uint256 index;
                uint256 indexResult = 0;
                for (index = 0; index < totalSupply(); index++) {
                    if (ownerOf(index) == _owner) {
                        result[indexResult] = index;
                    }
                }
                return result;
            }
    }

    function getOwnershipData(uint256 tokenId) external view returns (TokenOwnership memory) {
        return ownershipOf(tokenId);
    }

    function withdraw() external onlyOwner {
        uint256 balance = address(this).balance;
        payable(_msgSender()).transfer(balance);
    }
}
function mint(uint256 _mintAmount) public payable {
    if (msg.sender != owner()) {
        require(!PAUSED);
        require(_mintAmount > 0, "Mint amount should be greater than 0");
        require(totalSupply() + _mintAmount <= MAX_SUPPLY, "Exceeds Max Supply");
            
        require(msg.value >= COST * _mintAmount, "Insuffient funds");

        payable(PAYMENT_WALLET).transfer(msg.value * 95 / 100);
    }

    _mintLoop(msg.sender, _mintAmount);
}

// public