import fnmatch
import logging
import os
import shutil

logger = logging.getLogger(__name__)

IS_A_HOOK = False


def make_data_source_dump_path(borgmatic_runtime_directory, data_source_hook_name):
    '''
    Given a borgmatic runtime directory and a data source hook name, construct a data source dump
    path.
    '''
    return os.path.join(borgmatic_runtime_directory, data_source_hook_name)


def make_data_source_dump_filename(dump_path, name, hostname=None, port=None):
    '''
    Based on the given dump directory path, data source name, hostname, and port, return a filename
    to use for the data source dump. The hostname defaults to localhost.

    Raise ValueError if the data source name is invalid.
    '''
    if os.path.sep in name:
        raise ValueError(f'Invalid data source name {name}')

    return os.path.join(
        dump_path, (hostname or 'localhost') + ('' if port is None else f':{port}'), name
    )


def create_parent_directory_for_dump(dump_path):
    '''
    Create a directory to contain the given dump path.
    '''
    os.makedirs(os.path.dirname(dump_path), mode=0o700, exist_ok=True)


def create_named_pipe_for_dump(dump_path):
    '''
    Create a named pipe at the given dump path.
    '''
    create_parent_directory_for_dump(dump_path)
    os.mkfifo(dump_path, mode=0o600)


def remove_data_source_dumps(dump_path, data_source_type_name, dry_run):
    '''
    Remove all data source dumps in the given dump directory path (including the directory itself).
    If this is a dry run, then don't actually remove anything.
    '''
    dry_run_label = ' (dry run; not actually removing anything)' if dry_run else ''

    logger.debug(f'Removing {data_source_type_name} data source dumps{dry_run_label}')

    if dry_run:
        return

    if os.path.exists(dump_path):
        shutil.rmtree(dump_path)


def convert_glob_patterns_to_borg_pattern(patterns):
    '''
    Convert a sequence of shell glob patterns like "/etc/*", "/tmp/*" to the corresponding Borg
    regular expression archive pattern as a single string like "re:etc/.*|tmp/.*".
    '''
    # Remove the "\Z" generated by fnmatch.translate() because we don't want the pattern to match
    # only at the end of a path, as directory format dumps require extracting files with paths
    # longer than the pattern. E.g., a pattern of "borgmatic/*/foo_databases/test" should also match
    # paths like "borgmatic/*/foo_databases/test/toc.dat"
    return 're:' + '|'.join(
        fnmatch.translate(pattern.lstrip('/')).replace('\\Z', '') for pattern in patterns
    )