Customized NFT collection

Hello I try to create a slightly customized NFT collection.
About this collection
1) only non-fungible NFT tokens
2) Royalties with support for major marketplaces.
3) Be secure and tested
4) Limits for max supply and max nfts per address
5) Has set metadata onchain except image which is uploaded on IPFS
6) The price of mint is arbitrary, can be zero or more
7) option to change royalties receiver
Main questions
A) use ERC1155, ERC721 or another ERC standard?
From what I read ERC1155 seems more optimazed(gas efficency, security), on the other hand ERC721 seems more used and mayby also trusted?
B) not sure how to ensure the security of contract. More suitable is now for me spend some time by learning and understanding how the things works, than order and pay someone for audit. What could be best options for this case? I try go through hacking tasks like Ethernaut. Post this contract on forums and platforms which are focused on this topic?
Here is what I put together so far. It works, just not sure how much is it safe and what can be written in better way.
I am also open to participate on some wizard like openzzepelin https://wizard.openzeppelin.com/ or ERC721 studio https://www.721.so/

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

import '@openzeppelin/contracts/token/ERC1155/ERC1155.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/utils/Counters.sol';
import '@openzeppelin/contracts/interfaces/IERC2981.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
import '@openzeppelin/contracts/utils/Base64.sol';

contract NftTest is ERC1155, IERC2981, Ownable, ReentrancyGuard {
    /**
     * @dev `_uri` is set only to satisfy the constructor of ERC1155. Otherwise uri for NFT token metadata is set on-chain.
     */
    constructor(string memory _uri) ERC1155(_uri) {
        _royaltyReciever = owner();
    }

    /** MINTING **/

    using Counters for Counters.Counter;

    // counting of minted NFTs by address
    mapping(address => uint256) private mintCountMap;

    uint256 public constant MAX_SUPPLY = 1000;

    uint256 public constant MINT_LIMIT_PER_WALLET = 7;

    Counters.Counter private supplyCounter;

    event PermanentURI(string _value, uint256 indexed _id);

    function allowedMintCount(address minter) public view returns (uint256) {
        return MINT_LIMIT_PER_WALLET - mintCountMap[minter];
    }

    function updateMintCount(address minter, uint256 count) private {
        mintCountMap[minter] += count;
    }

    function _checkIfCanMint() internal {
        if (allowedMintCount(msg.sender) >= 1) {
            updateMintCount(msg.sender, 1);
        } else {
            revert('Minting limit exceeded');
        }
        require(
            Counters.current(supplyCounter) < MAX_SUPPLY,
            'Exceeds max supply'
        );
    }

    function mintedNFTs() public view returns (uint256) {
        return Counters.current(supplyCounter);
    }

    /**
     * @dev
     * `id` for token id in _mint is `Counters.current(supplyCounter)`. Each NFT token has unique id
     * `amount` in _mint is set 1 to restrict multimint
     * `data` in _mint is set to `''` because are not used in this contract
     */
    function mint(address account)
        public
        payable
        virtual
        nonReentrant
        returns (uint256)
    {
        _checkIfCanMint();
        _mint(account, Counters.current(supplyCounter), 1, '');
        emit PermanentURI(
            uri(Counters.current(supplyCounter)),
            Counters.current(supplyCounter)
        );
        supplyCounter.increment();
        return Counters.current(supplyCounter);
    }

    /** PAYOUT **/

    function withdraw() public nonReentrant {
        uint256 balance = address(this).balance;

        Address.sendValue(payable(owner()), balance);
    }

    /** ROYALTIES **/

    /**
     * @dev _royaltyReciever is accepted by some marketplaces.
     * Other marketplaces may send royalty based on specification in contractURI metadata.
     */
    address private _royaltyReciever = address(this);

    function _setRoyaltyReciever(address newRoyaltyReceiver)
        internal
        onlyOwner
    {
        require(newRoyaltyReceiver != address(0), 'Invalid address');
        _royaltyReciever = newRoyaltyReceiver;
    }

    function setRoyaltyReciever(address newRoyaltyReceiver) external onlyOwner {
        _setRoyaltyReciever(newRoyaltyReceiver);
    }

    function getRoyaltyReciever() public view returns (address) {
        return _royaltyReciever;
    }

    function royaltyInfo(uint256, uint256 salePrice)
        external
        view
        override
        returns (address receiver, uint256 royaltyAmount)
    {
        return (_royaltyReciever, (salePrice * 500) / 10000);
    }

    // EIP2981 standard Interface return. Adds to ERC1155 and ERC165 Interface returns.
    function supportsInterface(bytes4 interfaceId)
        public
        view
        virtual
        override(ERC1155, IERC165)
        returns (bool)
    {
        return (interfaceId == type(IERC2981).interfaceId ||
            super.supportsInterface(interfaceId));
    }

    /** METADATA **/
    /**
     * @dev Collection metadata based on opensea standards
     */
    function contractURI() public view returns (string memory) {
        bytes memory dataURI = abi.encodePacked(
            '{',
            '"name": "some name",',
            '"description": "text about this NFTs",',
            '"image": "ipfs://hash",',
            '"external_link": "https://example.xyz",',
            '"seller_fee_basis_points": 500,',
            '"fee_recipient": "',
            Strings.toHexString(uint160(_royaltyReciever), 20),
            '"',
            '}'
        );
        return
            string(
                abi.encodePacked(
                    'data:application/json;base64,',
                    Base64.encode(dataURI)
                )
            );
    }
    function uri(uint256 tokenId)
        public
        view
        virtual
        override
        returns (string memory)
    {
        bytes memory dataURI = abi.encodePacked(
            '{',
            '"name": "some name',
            Strings.toString(tokenId),
            '",',
            '"description": "text about this NFTs",',
            '"image": "ipfs://hash"',
            '}'
        );
        return
            string(
                abi.encodePacked(
                    'data:application/json;base64,',
                    Base64.encode(dataURI)
                )
            );
    }
}