"""
The tool to check the availability or syntax of domains, IPv4, IPv6 or URL.

::


    ██████╗ ██╗   ██╗███████╗██╗   ██╗███╗   ██╗ ██████╗███████╗██████╗ ██╗     ███████╗
    ██╔══██╗╚██╗ ██╔╝██╔════╝██║   ██║████╗  ██║██╔════╝██╔════╝██╔══██╗██║     ██╔════╝
    ██████╔╝ ╚████╔╝ █████╗  ██║   ██║██╔██╗ ██║██║     █████╗  ██████╔╝██║     █████╗
    ██╔═══╝   ╚██╔╝  ██╔══╝  ██║   ██║██║╚██╗██║██║     ██╔══╝  ██╔══██╗██║     ██╔══╝
    ██║        ██║   ██║     ╚██████╔╝██║ ╚████║╚██████╗███████╗██████╔╝███████╗███████╗
    ╚═╝        ╚═╝   ╚═╝      ╚═════╝ ╚═╝  ╚═══╝ ╚═════╝╚══════╝╚═════╝ ╚══════╝╚══════╝

Provides the cleaning interface.

Author:
    Nissar Chababy, @funilrys, contactTATAfunilrysTODTODcom

Special thanks:
    https://pyfunceble.github.io/special-thanks.html

Contributors:
    https://pyfunceble.github.io/contributors.html

Project link:
    https://github.com/funilrys/PyFunceble

Project documentation:
    https://pyfunceble.readthedocs.io/en/dev/

Project homepage:
    https://pyfunceble.github.io/

License:
::


    Copyright 2017, 2018, 2019, 2020 Nissar Chababy

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
"""

from os import sep as directory_separator
from os import walk

import PyFunceble


class Clean:
    """
    Provide the cleaning logic.

    .. note::
        By cleaning we mean the cleaning of the :code:`output` directory.

    :param list_to_test: The list of domains we are testing.
    :type list_to_test: list|None

    :param bool clean_all:
        Tell the subsystem if we need to clean all.
        Which include, of course, the output directory but also
        all other file(s) generated by our system.
    :param str file_path:
        The path to the file we tested.

        .. note::
            This is only relevant if you use the MariaDB/MySQL database.
    """

    def __init__(self, clean_all=False, file_path=None):
        # We clean the output directory.
        self.almost_everything(clean_all, file_path)

    @classmethod
    def file_to_delete(cls, all_files=False):
        """
        Return the list of file to delete.
        """

        # We initiate the directory we have to look for.
        directory = "{0}{1}".format(
            PyFunceble.OUTPUT_DIRECTORY, PyFunceble.OUTPUTS.parent_directory
        )

        if not directory.endswith(directory_separator):  # pragma: no cover
            # For safety, if it does not ends with the directory separator, we append it
            # to its end.
            directory += directory_separator

        # We initiate a variable which will save the list of file to delete.
        result = []

        for root, _, files in walk(directory):
            # We walk in the directory and get all files and sub-directories.

            for file in files:
                # If there is files in the current sub-directory, we loop
                # through the list of files.

                if file in [".gitignore", ".keep"]:
                    continue

                if (
                    not all_files and "logs" in root and ".log" in file
                ):  # pragma: no cover
                    continue

                # The file is not into our list of file we do not have to delete.

                if root.endswith(directory_separator):
                    # The root ends with the directory separator.

                    # We construct the path and append the full path to the result.
                    result.append(root + file)
                else:
                    # The root directory does not ends with the directory separator.

                    # We construct the path by appending the directory separator
                    # between the root and the filename and append the full path to
                    # the result.
                    result.append(root + directory_separator + file)  # pragma: no cover

        # We return our list of file to delete.
        return result

    @classmethod
    def databases_to_delete(cls):  # pragma: no cover
        """
        Set the databases files to delete.
        """

        # We initate the result variable.
        result = []

        if PyFunceble.CONFIGURATION.db_type == "json":
            # We initiate the directory we have to look for.
            directory = PyFunceble.CONFIG_DIRECTORY

            # We append the dir_structure file.
            result.append(
                "{0}{1}".format(
                    directory, PyFunceble.OUTPUTS.default_files.dir_structure
                )
            )

            # We append the iana file.
            result.append(
                "{0}{1}".format(directory, PyFunceble.OUTPUTS.default_files.iana)
            )

            # We append the public suffix file.
            result.append(
                "{0}{1}".format(
                    directory, PyFunceble.OUTPUTS.default_files.public_suffix
                )
            )

            # We append the inactive database file.
            result.append(
                "{0}{1}".format(directory, PyFunceble.OUTPUTS.default_files.inactive_db)
            )

            # We append the mining database file.
            result.append(
                "{0}{1}".format(directory, PyFunceble.OUTPUTS.default_files.mining)
            )

        return result

    def almost_everything(self, clean_all=False, file_path=False):
        """
        Delete almost all discovered files.

        :param bool clean_all:
            Tell the subsystem if we have to clean everything instesd
            of almost everything.
        """

        if (
            "do_not_clean" not in PyFunceble.INTERN
            or not PyFunceble.INTERN["do_not_clean"]
        ):
            # We get the list of file to delete.
            to_delete = self.file_to_delete(clean_all)

            if (
                not PyFunceble.abstracts.Version.is_local_cloned() and clean_all
            ):  # pragma: no cover
                to_delete.extend(self.databases_to_delete())

            for file in to_delete:
                # We loop through the list of file to delete.

                # And we delete the currently read file.
                PyFunceble.helpers.File(file).delete()

                PyFunceble.LOGGER.info(f"Deleted: {file}")

            if clean_all:  # pragma: no cover
                to_avoid = ["whois"]
            else:
                to_avoid = ["whois", "auto_continue", "inactive", "mining"]

            if not file_path:
                query = "DELETE FROM {0}"
            else:  # pragma: no cover
                query = "DELETE FROM {0} WHERE file_path = %(file_path)s"

            if PyFunceble.CONFIGURATION.db_type in [
                "mariadb",
                "mysql",
            ]:  # pragma: no cover

                with PyFunceble.engine.MySQL() as connection:
                    for database_name in [
                        y
                        for x, y in PyFunceble.engine.MySQL.tables.items()
                        if x not in to_avoid
                    ]:
                        lquery = query.format(database_name)

                        with connection.cursor() as cursor:
                            cursor.execute(lquery, {"file_path": file_path})

                            PyFunceble.LOGGER.info(
                                "Cleaned the data related to "
                                f"{repr(file_path)} from the {database_name} table."
                            )

            if (
                not PyFunceble.abstracts.Version.is_local_cloned() and clean_all
            ):  # pragma: no cover
                PyFunceble.load_config()

                PyFunceble.LOGGER.info("Reloaded configuration.")
