from functools import reduce
from os import listdir
from os.path import join, splitext
from re import M
from re import search as re_search
from typing import Any, Union

from docopt import docopt
from snakypy.helpers.ansi import FG, NONE
from snakypy.helpers.logging import Log

from snakypy.zshpower import __info__
from snakypy.zshpower.config import menu


def get_key(dictionary: dict, *args) -> Union[str, bool, dict]:
    """
    Function to get keys from a dictionary recursively without errors.
    If the key does not exist it returns an empty dictionary.

    Args:
        dictionary ([dict]): Receive a dictionary

    Returns:
        [str, bool]: Returning a str or a boolean if the object is True or False.
    """
    data = reduce(lambda c, k: c.get(k, {}), args, dictionary)
    if data == {}:
        return ""
    return data


def read_file_log(file: str, logfile: str) -> str:
    """
    Read a file with log creation option if it does not exist
    """
    try:
        with open(file) as f:
            return f.read()
    except FileNotFoundError as err:
        Log(filename=logfile).record(
            f"The {file} file was not found.", colorize=True, level="error"
        )
        raise FileNotFoundError(f"The {file} file was not found.", err)


def arguments(argv: Any = None) -> dict:
    formatted_version = (
        f"{__info__['name']} version: {FG().CYAN}{__info__['version']}{NONE}"
    )
    data = docopt(menu.options, argv=argv, version=formatted_version)
    return data


def get_zsh_theme(file: str, logfile: str) -> Union[tuple, bool]:
    """
    Get the current theme contained in the .zshrc file if using Oh My ZSH
    """
    current_file = read_file_log(file, logfile)
    m = re_search(r"ZSH_THEME=\".*", current_file)
    if m is not None:
        theme_var = m.group(0)
        lst = theme_var.split("=")
        theme_name = [s.strip('"') for s in lst][1]
        return theme_name, theme_var
    return False


def current_plugins(file: str, logfile: str) -> list:
    """
    Get current plugins from .zshrc file if using Oh My ZSH
    """
    current_file = read_file_log(file, logfile)
    m = re_search(r"^plugins=\(.*", current_file, flags=M)
    if m is not None:
        get = m.group(0)
        lst = get.split("=")
        current = [i.strip('"').replace("(", "").replace(")", "") for i in lst][1]
        return current.split()
    return []


def get_line(file: str, line: str, logfile: str) -> Union[str, bool]:
    """
    Get a given line from a given file
    """
    current_file = read_file_log(file, logfile)
    m = re_search(rf"{line}", current_file)
    if m is not None:
        return m.group(0)
    return False


# TODO: DEPRECATED
# def verify_objects(directory: str, /, data: dict, strictly: bool = False) -> bool:
#     """
#     Checks whether there are objects from a particular directory.
#     These can be folders, files and file extensions.
#     """
#     if type(data) is not dict:
#         raise TypeError("Data parameter must be a dictionary.")
#
#     if "files" not in data or "folders" not in data or "extensions" not in data:
#         raise TypeError(
#             "The dictionary does not contain one of the following keys: 'files', 'folders', 'extensions'."
#         )
#
#     def finder_files_folders():
#         if data["files"] or data["folders"]:
#             files_folders = data["files"] + data["folders"]
#             for obj in listdir(directory):
#                 if strictly is False:
#                     if obj in files_folders:
#                         return True
#                 else:
#                     if obj not in files_folders:
#                         return False
#
#         return False
#
#     def finder_extensions():
#         if data["extensions"]:
#             lst = []
#             for ext in data["extensions"]:
#                 for file in listdir(directory):
#                     if file.endswith(ext):
#                         lst.append(join(directory, file))
#
#             e = [splitext(f)[-1] for f in lst]
#             for ext in data["extensions"]:
#                 if ext in e:
#                     return True
#         return False
#
#     if finder_files_folders() is False and finder_extensions() is False:
#         return False
#
#     return True
#


def verify_objects(directory: str, /, data: dict) -> bool:
    """
    Checks whether there are objects from a particular directory.
    These can be folders, files and file extensions.
    """
    if type(data) is not dict:
        raise TypeError("Data parameter must be a dictionary.")

    if "files" not in data or "folders" not in data or "extensions" not in data:
        raise TypeError(
            "The dictionary does not contain one of the following keys: 'files', 'folders', 'extensions'."
        )

    objects_in_directory = listdir(directory)

    def files_folders(key):

        # The "strictly" key will check whether the dictionary keys (files and folders) are tuples or lists.
        # If you use tuples, it means that the search must be rigorous, that is, if there is no such object,
        # the return will always be False.

        # If you use list in "files" or "folders", the search is tolerant, that is, if it finds a single object,
        # the return will always be True.

        strictly = False

        if data[key]:
            if type(data[key]) is tuple:
                strictly = True
            for item in data[key]:
                if strictly is False:
                    if item in objects_in_directory:
                        return True
                    return False
                else:
                    if item not in objects_in_directory:
                        return False
                    return True
        return False

    def finder_extensions():
        if data["extensions"]:
            lst = []
            for ext in data["extensions"]:
                for file in objects_in_directory:
                    if file.endswith(ext):
                        lst.append(join(directory, file))

            e = [splitext(f)[-1] for f in lst]
            for ext in data["extensions"]:
                if ext in e:
                    return True
        return False

    files = files_folders("files")
    folders = files_folders("folders")
    extensions = finder_extensions()

    if (files is False and folders is False) and extensions is False:
        return False

    return True

from functools import reduce
from os import listdir
from os.path import join, splitext
from re import M
from re import search as re_search
from typing import Any, Union

from docopt import docopt
from snakypy.helpers.ansi import FG, NONE
from snakypy.helpers.logging import Log

from snakypy.zshpower import __info__
from snakypy.zshpower.config import menu


def get_key(dictionary: dict, *args) -> Union[str, bool, dict]:
    """
    Function to get keys from a dictionary recursively without errors.
    If the key does not exist it returns an empty dictionary.

    Args:
        dictionary ([dict]): Receive a dictionary

    Returns:
        [str, bool]: Returning a str or a boolean if the object is True or False.
    """
    data = reduce(lambda c, k: c.get(k, {}), args, dictionary)
    if data == {}:
        return ""
    return data


def read_file_log(file: str, logfile: str) -> str:
    """
    Read a file with log creation option if it does not exist
    """
    try:
        with open(file) as f:
            return f.read()
    except FileNotFoundError as err:
        Log(filename=logfile).record(
            f"The {file} file was not found.", colorize=True, level="error"
        )
        raise FileNotFoundError(f"The {file} file was not found.", err)


def arguments(argv: Any = None) -> dict:
    formatted_version = (
        f"{__info__['name']} version: {FG().CYAN}{__info__['version']}{NONE}"
    )
    data = docopt(menu.options, argv=argv, version=formatted_version)
    return data


def get_zsh_theme(file: str, logfile: str) -> Union[tuple, bool]:
    """
    Get the current theme contained in the .zshrc file if using Oh My ZSH
    """
    current_file = read_file_log(file, logfile)
    m = re_search(r"ZSH_THEME=\".*", current_file)
    if m is not None:
        theme_var = m.group(0)
        lst = theme_var.split("=")
        theme_name = [s.strip('"') for s in lst][1]
        return theme_name, theme_var
    return False


def current_plugins(file: str, logfile: str) -> list:
    """
    Get current plugins from .zshrc file if using Oh My ZSH
    """
    current_file = read_file_log(file, logfile)
    m = re_search(r"^plugins=\(.*", current_file, flags=M)
    if m is not None:
        get = m.group(0)
        lst = get.split("=")
        current = [i.strip('"').replace("(", "").replace(")", "") for i in lst][1]
        return current.split()
    return []


def get_line(file: str, line: str, logfile: str) -> Union[str, bool]:
    """
    Get a given line from a given file
    """
    current_file = read_file_log(file, logfile)
    m = re_search(rf"{line}", current_file)
    if m is not None:
        return m.group(0)
    return False


# TODO: DEPRECATED
# def verify_objects(directory: str, /, data: dict, strictly: bool = False) -> bool:
#     """
#     Checks whether there are objects from a particular directory.
#     These can be folders, files and file extensions.
#     """
#     if type(data) is not dict:
#         raise TypeError("Data parameter must be a dictionary.")
#
#     if "files" not in data or "folders" not in data or "extensions" not in data:
#         raise TypeError(
#             "The dictionary does not contain one of the following keys: 'files', 'folders', 'extensions'."
#         )
#
#     def finder_files_folders():
#         if data["files"] or data["folders"]:
#             files_folders = data["files"] + data["folders"]
#             for obj in listdir(directory):
#                 if strictly is False:
#                     if obj in files_folders:
#                         return True
#                 else:
#                     if obj not in files_folders:
#                         return False
#
#         return False
#
#     def finder_extensions():
#         if data["extensions"]:
#             lst = []
#             for ext in data["extensions"]:
#                 for file in listdir(directory):
#                     if file.endswith(ext):
#                         lst.append(join(directory, file))
#
#             e = [splitext(f)[-1] for f in lst]
#             for ext in data["extensions"]:
#                 if ext in e:
#                     return True
#         return False
#
#     if finder_files_folders() is False and finder_extensions() is False:
#         return False
#
#     return True
#


def verify_objects(directory: str, /, data: dict) -> bool:
    """
    Checks whether there are objects from a particular directory.
    These can be folders, files and file extensions.
    """
    if type(data) is not dict:
        raise TypeError("Data parameter must be a dictionary.")

    if "files" not in data or "folders" not in data or "extensions" not in data:
        raise TypeError(
            "The dictionary does not contain one of the following keys: 'files', 'folders', 'extensions'."
        )

    objects_in_directory = listdir(directory)

    def files_folders(key):

        # The "strictly" key will check whether the dictionary keys (files and folders) are tuples or lists.
        # If you use tuples, it means that the search must be rigorous, that is, if there is no such object,
        # the return will always be False.

        # If you use list in "files" or "folders", the search is tolerant, that is, if it finds a single object,
        # the return will always be True.

        strictly = False

        if data[key]:
            if type(data[key]) is tuple:
                strictly = True
            for item in data[key]:
                if strictly is False:
                    if item in objects_in_directory:
                        return True
                    return False
                else:
                    if item not in objects_in_directory:
                        return False
                    return True
        return False

    def finder_extensions():
        if data["extensions"]:
            lst = []
            for ext in data["extensions"]:
                for file in objects_in_directory:
                    if file.endswith(ext):
                        lst.append(join(directory, file))

            e = [splitext(f)[-1] for f in lst]
            for ext in data["extensions"]:
                if ext in e:
                    return True
        return False

    files = files_folders("files")
    folders = files_folders("folders")
    extensions = finder_extensions()

    if (files is False and folders is False) and extensions is False:
        return False

    return True

Function to get keys from a dictionary recursively without errors.     If the key does not exist it returns an empty dictionary.      Args:         dictionary ([dict]): Receive a dictionary      Returns:         [str, bool]: Returning a str or a boolean if the object is True or False. Read a file with log creation option if it does not exist Get the current theme contained in the .zshrc file if using Oh My ZSH Get current plugins from .zshrc file if using Oh My ZSH Get a given line from a given file # TODO: DEPRECATED # def verify_objects(directory: str, /, data: dict, strictly: bool = False) -> bool: #     """ #     Checks whether there are objects from a particular directory. #     These can be folders, files and file extensions. #     """ #     if type(data) is not dict: #         raise TypeError("Data parameter must be a dictionary.") # #     if "files" not in data or "folders" not in data or "extensions" not in data: #         raise TypeError( #             "The dictionary does not contain one of the following keys: 'files', 'folders', 'extensions'." #         ) # #     def finder_files_folders(): #         if data["files"] or data["folders"]: #             files_folders = data["files"] + data["folders"] #             for obj in listdir(directory): #                 if strictly is False: #                     if obj in files_folders: #                         return True #                 else: #                     if obj not in files_folders: #                         return False # #         return False # #     def finder_extensions(): #         if data["extensions"]: #             lst = [] #             for ext in data["extensions"]: #                 for file in listdir(directory): #                     if file.endswith(ext): #                         lst.append(join(directory, file)) # #             e = [splitext(f)[-1] for f in lst] #             for ext in data["extensions"]: #                 if ext in e: #                     return True #         return False # #     if finder_files_folders() is False and finder_extensions() is False: #         return False # #     return True # Checks whether there are objects from a particular directory.     These can be folders, files and file extensions. # The "strictly" key will check whether the dictionary keys (files and folders) are tuples or lists. # If you use tuples, it means that the search must be rigorous, that is, if there is no such object, # the return will always be False. # If you use list in "files" or "folders", the search is tolerant, that is, if it finds a single object, # the return will always be True.