contract StrikeApes is ERC721Common, ReentrancyGuard {
    using Counters for Counters.Counter;
    using Strings for uint256;

    Counters.Counter private _tokenIdCounter;

    bool public presaleActive;
    bool public saleActive;
    uint8 public constant MAX_PRESALE_MINT = 5;
    uint8 public constant MAX_MINT = 30;
    uint16 public constant MAX_ITEMS = 6_500;
    uint256 public PRESALE_PRICE = 0.032 ether;
    uint256 public PRICE = 0.045 ether;

    mapping(address => uint) public presaleWhitelist;

    constructor(
        string memory name,
        string memory symbol
    ) ERC721Common(name, symbol) {}

    function presaleMint(address _to, uint16 _count) public payable 
        nonReentrant
        whenNotPaused {
        require(presaleActive == true, "Sale has not yet started");
        require(totalSupply() + _count <= MAX_ITEMS, "Max limit");
        require(presaleWhitelist[msg.sender] > 0, "You are not on white list");
        require(_count <= presaleWhitelist[msg.sender], "Exceeds number");
        require(msg.value >= PRESALE_PRICE * _count, "Value below price");

        presaleWhitelist[msg.sender] = presaleWhitelist[msg.sender] - _count;

        for (uint16 i = 0; i < _count; i++) {
            safeMint(_to);
        }
    }

    function mint(address _to, uint16 _count) public payable 
        nonReentrant
        whenNotPaused {
        require(saleActive == true, "Sale has not yet started");
        require(totalSupply() + _count <= MAX_ITEMS, "Max limit");
        require(_count <= MAX_MINT, "Exceeds number");
        require(msg.value >= PRICE * _count, "Value below price");

        for (uint16 i = 0; i < _count; i++) {
            safeMint(_to);
        }
    }

    function mintReserve(address _to, uint16 _count) public onlyOwner {
        require(totalSupply() + _count <= MAX_ITEMS, "Sold out");
        
        for (uint16 i = 0; i < _count; i++) {
            safeMint(_to);
        }
    }

    function safeMint(address to) internal {
        uint256 tokenId = _tokenIdCounter.current();
        _tokenIdCounter.increment();
        _safeMint(to, tokenId);
    }

    function editToPresale(address[] calldata addresses) external onlyOwner {
        for (uint256 i = 0; i < addresses.length; i++) {
            presaleWhitelist[addresses[i]] = MAX_PRESALE_MINT;
        }
    }

    function setPresaleStatus(bool _status) external onlyOwner {
        presaleActive = _status;
    }

    function setSaleStatus(bool _status) external onlyOwner {
        saleActive = _status;
    }

    function setPresalePrice(uint256 _price) external onlyOwner {
        PRESALE_PRICE = _price;
    }

    function setPrice(uint256 _price) external onlyOwner {
        PRICE = _price;
    }

    /// @notice Prefix for tokenURI return values.
    string public baseTokenURI;

    /// @notice Set the baseTokenURI.
    function setBaseTokenURI(string memory baseTokenURI_) external onlyOwner {
        baseTokenURI = baseTokenURI_;
    }

    /// @notice Returns the token's metadata URI.
    function tokenURI(uint256 tokenId)
        public
        view
        override
        tokenExists(tokenId)
        returns (string memory)
    {
        return bytes(baseTokenURI).length > 0 ? string(abi.encodePacked(baseTokenURI, tokenId.toString())) : "";
    }

    /**
    @notice Returns total number of existing tokens.
    @dev Using ERC721Enumerable is unnecessarily expensive wrt gas. However
    Etherscan uses totalSupply() so we provide it here.
     */
    function totalSupply() public view returns (uint) {
        return _tokenIdCounter.current();
    }

    function withdrawAll() public payable onlyOwner {
        _widthdraw(msg.sender, address(this).balance);
    }

    function _widthdraw(address _address, uint256 _amount) private {
        (bool success,) = _address.call{value : _amount}("");
        require(success, "Transfer failed.");
    }
}
function totalSupply() public view returns (uint) {
    return _tokenIdCounter.current();
}

/**
 @notice Returns total number of existing tokens.
 @dev Using ERC721Enumerable is unnecessarily expensive wrt gas. However
 Etherscan uses totalSupply() so we provide it here.
 */