from wox.logger.logger_setup import wox_logger
from wox.utils import sort_set
from wox.wox_exceptions import (
    MissingWoxKeywordError,
    NoTaskError,
    TaskNotFoundError
)


def configuration_creation(env, settings, envlist):
    """
        Creates the configuration to execute task.

        Parameters
        ----------
        env : str
            The name of the virtual environment.
        settings : dict
            Settings exctracted from the configuration .toml file.
        envlist : list
            List of virtual environments used during the wox session.

        Returns
        -------
        dict

        Notes
        -----
        When an env has specific settings in its subsection, they are
        merged with the settings from the main section to create a
        complete configuration.
        This is done with an union between the two dict. When two keys
        are identical, the key from the first dict is kept.
        The union operator was introduced in Python 3.9.
    """

    wox_logger.debug('Creation of configuration for the current task.')

    base_config = {
        key: value
        for key, value in settings.items()
        if key not in envlist and not isinstance(value, dict)
    }

    env_config = settings.get(env, {})

    config = base_config | env_config

    wox_logger.debug(f'Configuration: {config}')

    return config

def session_setup(cli_options, wox_data):
    """
        Resolves session configuration and selected tasks based on command-line options
        and the content of the sections of the .toml file.

        Notes
        -----
        Command-line options take priority over configuration values.

        If both ``--task`` and ``--exclude-task`` are present among CLI options,
        ``--task`` has priority over ``--exclude-task``, without denying it:
        a task appearing in both ``--task`` and ``--exclude-task`` is included.
        All other tasks listed in ``--exclude-task`` are excluded.

        Parameters
        ----------
        cli_options : dict
            Options provided on the command line.
        wox_data : dict
            Information provided by the .toml file.

        Returns
        -------
        wox_configuration : dict
            The configuration extracted from the ``wox_configuration`` section
            of the .toml file.
        wox_data : dict
            Dictionnary with the tasks declared in the .toml file,  filtered
            according to wox configuration and command-line options.

        Raises
        ------
        MissingWoxKeywordError
            Required wox keyword missing in .toml file.
        NoTaskError
            No tasks left with use of --task and --exclude-task.
        TaskNotFoundError
            The task is not present in the .toml file.
    """

    try:
        wox_configuration = wox_data.pop('wox_configuration')
    except KeyError as e:
        raise MissingWoxKeywordError(e)

    all_tasks = set(wox_data.keys())
    if not all_tasks:
        raise NoTaskError
    cli_task = set(cli_options.get('task') or [])
    cli_exclude = set(cli_options.get('exclude_task') or [])
    default = set(wox_configuration.get('wox_session_default') or [])

    if cli_task:
        missing_tasks = cli_task - all_tasks
        sorted_missing_tasks = sort_set(missing_tasks, cli_options['task'])
        if missing_tasks:
            raise TaskNotFoundError(
                ', '.join([f"'{task}'" for task in sorted_missing_tasks])
            )
        session_tasks = cli_task
    elif default:
        session_tasks = default
    else:
        session_tasks = all_tasks

    if cli_exclude:
        missing_tasks = cli_exclude - all_tasks
        sorted_missing_tasks = sort_set(missing_tasks, cli_options['exclude_task'])
        if missing_tasks:
            raise TaskNotFoundError(
                ', '.join([f"'{task}'" for task in sorted_missing_tasks])
            )
        session_tasks.difference_update(cli_exclude)
        if not session_tasks:
            raise NoTaskError

    sorted_tasks = sort_set(session_tasks, wox_data.keys())

    wox_data = {task: wox_data[task] for task in sorted_tasks}

    return wox_configuration, wox_data
