Getting an DeclarationError: Identifier not found or not unique while using counters

Hello,
I am a newbie to coding in solidity and I am trying to deploy a smart contract. I got an error stating that the DeclarationError: Identifier not found or not unique. using Counters for Counters.counter;.
Please find the code below.

pragma solidity ^0.8.4;
// Importing required libraries
/*
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/token/ERC721/ERC721.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/access/Ownable.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/utils/Counters.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/591c12d22de283a297e2b551175ccc914c938391/contracts/token/ERC721/extensions/ERC721Enumerable.sol";
*/


import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 

 // This is a simple NFT contract
 //Start of a contract
 //INitialising contract as a ERC721, ERC721Enumerable, Ownable contract.
 contract NFTCollection is ERC721, ERC721Enumerable, Ownable {
    using Counters for Counters.counter;

    // Specifing the maximum supply
    uint256 maxSupply = 1000000;
    // Initiatina a counter to store to be able to use Counters on uint265 without impacting the rest of the uint256 in the contract.
    //Counter helps to find every function from a single library to a type to reduce gass fee.
    Counters.Counter private _tokenIDCounter;
    // Initialising a constructor.
    constructor(string memory _name, string memory _symbol)
        ERC721(_name, _symbol){}
        // ERC721 interface is initialised and the _name, _symbol details aere passed in to hold.
        //End of constructor. 
        //Start of function mint.
        //This function is used to mint ERC721 tokens. 
        //Mint function adds the capability to mint ERC721 tokens and assign it to a address which accepts user address, number of tokens as arguments. 

        function mint(address _user, uint256 _amount) public {
            //Start of for loop
            for(uint256 i;i<_amount;i++)
            {
                //Incrementing the  _tokenIdCounter by 1 using increment function.
                _tokenIdCounter.increment();
                // Creating a variable which stores the current value of _tokenIdCounter.
                uint256 tokenId = _tokenIdcounter.current();
                //Using safemint to mint ERC721 Tokens.
                _safeMint(_user,tokenId);
            }
        }//End of function mint. 

        //Start of function tokensOfOwner
        // This function is used to keep track of the owners Tokens. 
        // The function seeks a owner address to check the number of tokens he owns. 
        function tokensOfOwner(address _owner) public view returns (uint256[] memory)
        {   // Creating a ownerTokenCount which stores the balance of the owner.
            uint256 ownerTokenCount = balanceOf(_owner);
            // Creating a memory variable and storing a array of ownerTokenCount. 
            uint256[] memory ownedTokenIds = new uint256[](ownerTokenCount);
            for (uint256 i; i < ownerTokenCount; ++i) {
                ownedTokenIds[i] = tokenOfOwnerByIndex(_owner, i);
            }//End of for loop
        return ownedTokenIds; //Return statement.
    }
    // Function overrides required by solidity
    function _beforeTokenTransfer(
        address from,
        address to,
        uint256 tokenId
    ) internal override(ERC721, ERC721Enumerable) {
        super._beforeTokenTransfer(from, to, tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public
        view
        override(ERC721, ERC721Enumerable)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }


 }

The error is as below.

DeclarationError: Identifier not found or not unique.
--> contracts/NftCollection.sol:20:24:
|
20 | using Counters for Counters.counter;
| ^^^^^^^^^^^^^^^^

according to your question:
the state variable name for the token id counter is different with what you call it on the mint function.

Counters.Counter private _tokenIDCounter;

vs

_tokenIdCounter.increment();

"ID vs Id"

some other things for improvements:

(1)
SPDX License Identifier should be provided at the very first of your contract
// SPDX-License-Identifier: MIT

(2)
add require special function to your mint function, to make sure the total token amounts to be minted plus recent total supply is not greater than maximum supply

// Mint
    function mint(address _user, uint256 _amount) public {
        require(_amount + totalSupply() < maxSupply, "Exceed maximum supply");

        for (uint256 i; i < _amount; i++) {
            uint256 tokenId = _tokenIdCounter.current();

            // Incrementing the  _tokenIdCounter by 1
            _tokenIdCounter.increment();
           
            _safeMint(_user,tokenId);
        }
    }

(3)
{ERC721Enumerable} is inherit to {ERC721}, so you don't have to inherit to {ERC721} on your contract

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract NFTCollection is ERC721Enumerable, Ownable {
...
}

(4)
metadata extension is optional according to EIP-721, but since {ERC721} from OpenZeppelin is applied the {IERC721Metadata}, the getter public functions: name(), symbol(), and tokenURI() are visible to your contract. and NFT marketplace (like OpenSea) is fetching the tokenURI when a new tokenId is minted and then showing its NFT metadata to their UI. so, i suggest you to construct the logic of the the tokenURI of your contract, by:

(a) add a state variable to store your "base" tokenURI

// Init base token URI
string private _baseTokenURI;

(b) overrides function baseURI() from {ERC721}

// Override {ERC721-_baseURI}
function _baseURI() internal view virtual override returns (string memory) {
     return _baseTokenURI;
 }

(c) add setter function to store the value to _baseTokenURI state variable. and since your contract inherit to {Ownable}, add onlyOwner modifier to the function -- means only owner of the contract who has an authorization to call this function (not everybody) as a best practice

// Set base token URI
function setBaseURI(string memory baseURI) public onlyOwner {
     // Assign baseURI value to _baseTokenURI
     _baseTokenURI = baseURI;
}

(d) and the last part is overriding the function tokenURI() itself, but before that we need to inherit to {Strings} library from OpenZeppelin

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract NFTCollection is ERC721Enumerable, Ownable {
    using Counters for Counters.Counter;
    using Strings for uint256;

}

and then

// Override {ERC721-tokenURI}
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        _requireMinted(tokenId);

        // Cache _baseURI()
        string memory baseURI = _baseURI();

        return bytes(baseURI).length > 0
            // If baseURI value is not empty, return
            ? string(abi.encodePacked(baseURI, "/", tokenId.toString()))
            // If empty, return empty string
            : "";
 }

and here's snippet of the whole code:

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

import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; 
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
import "@openzeppelin/contracts/utils/Strings.sol";

contract NFTCollection is ERC721Enumerable, Ownable {
    using Counters for Counters.Counter;
    using Strings for uint256;

    // Init the token id counter
    Counters.Counter private _tokenIdCounter;

    // Init maximum supply
    uint256 maxSupply = 1000000;

    // Init base token URI
    string private _baseTokenURI;
    
    // Constructor
    constructor(string memory _name, string memory _symbol) ERC721(_name, _symbol){ }

    // Mint
    function mint(address _user, uint256 _amount) public {
        require(_amount + totalSupply() < maxSupply, "Exceed maximum supply");

        for (uint256 i; i<_amount; i++) {
            uint256 tokenId = _tokenIdCounter.current();

            // Incrementing the  _tokenIdCounter by 1
            _tokenIdCounter.increment();
           
            _safeMint(_user,tokenId);
        }
    }

    // Set base token URI
    function setBaseURI(string memory baseURI) public onlyOwner {
        // Assign baseURI value to _baseTokenURI
        _baseTokenURI = baseURI;
    }

    // Override {ERC721-tokenURI}
    function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
        _requireMinted(tokenId);

        // Cache _baseURI()
        string memory baseURI = _baseURI();

        return bytes(baseURI).length > 0
            // If baseURI value is not empty, return
            ? string(abi.encodePacked(baseURI, "/", tokenId.toString()))
            // If empty, return empty string
            : "";
 }

    // This function is to return the [tokenIds] belong to the owner
    function tokensOfOwner(address _owner) public view returns (uint256[] memory) {   
        // Creating a ownerTokenCount which stores the balance of the owner.
        uint256 ownerTokenCount = balanceOf(_owner);

        // Creating a memory variable and storing a array of ownerTokenCount. 
        uint256[] memory ownedTokenIds = new uint256[](ownerTokenCount);

            for (uint256 i; i < ownerTokenCount; ++i) {
                ownedTokenIds[i] = tokenOfOwnerByIndex(_owner, i);
            }

        return ownedTokenIds;
    }

    // Override {ERC721-_baseURI}
    function _baseURI() internal view virtual override returns (string memory) {
        return _baseTokenURI;
    }
}

happy coding!