import os
import re
import glob
import yaml
import logging

logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())


def load_yaml(filename):
    """
    reads data stored in a yaml file to a dict which is returned
    """
    with open(filename, "r") as handle:
        return yaml.safe_load(handle)


def get_yamls_in_path(path=""):
    """
    recursively searches 'path' for files matching '*.yaml'
    :param path: string, path that is searched
    :return: list of strings, found yamls
    """
    return [f for f in glob.glob(os.path.join(path, "**/*.yaml"), recursive=True) if 'db_setup_config' not in f]


def write_yaml(dictionary, filename, *args, **kwargs):
    with open(filename, 'w') as handle:
        yaml.dump(dictionary, handle, *args, default_flow_style=False, **kwargs)


def is_existing_file_writeable(f):
    return os.access(f, os.W_OK)


def is_path_writable_or_can_be_created(f):
    if os.path.exists(f):
        return is_existing_file_writeable(f)
    else:
        parent_dir = os.path.dirname(f)
        if parent_dir == f:
            return False
        else:
            return is_path_writable_or_can_be_created(parent_dir)


def is_file_top_dir_writeable(f):
    return os.access(os.path.dirname(f), os.W_OK)


def replace_regex_in_file(fname, find, replace, dry_run=False):
    regex = re.compile(find, flags=re.MULTILINE)
    if not is_existing_file_writeable(fname):
        raise PermissionError(f"Could not manipulate file because it is not writeable:\n\t{fname}")
    with open(fname) as handle:
        content = handle.read()
        content = regex.sub(replace, content)
    if dry_run:
        print("Dry running...")
        print(content)
    else:
        with open(fname, "w") as handle:
            handle.write(content)
    logger.info(fname, "adapted")


def iter_file(fname):
    with open(fname, "r") as handle:
        for line in handle:
            line = line.strip()
            if len(line) > 0 and line[0] != "#":
                yield line.strip("\r\n")


def read_taxmap(taxmap, taxlevel):
    """
    read taxmap into dictionary, only taxlevel information is returned

    :param taxmap: tsv file, mapping accessions to taxa
    :param taxlevel: list of taxlevel names
    :return: dictionary, keys: accessions, values: tax
    """
    taxa = {}
    l = -len(taxlevel)+1
    with open(taxmap, "r") as handle:
        for line in handle:
            line = line.strip()
            if len(line) == 0:
                continue
            fields = line.split("\t")
            taxa[fields[0]] = fields[l:]
    return taxa


def get_headline(fname):
    if not os.path.exists(fname):
        raise FileNotFoundError(f"Could not read headline from file: {fname}")
    with open(fname, "r") as handle:
        return handle.readline().lstrip("#").strip()


def combine_spectra_into_one_list(spectra_per_pg_list):
    final_spectra_lst = []
    for spectra_per_sample in spectra_per_pg_list:
        if not spectra_per_sample:
            continue
        if not final_spectra_lst:
            final_spectra_lst = spectra_per_sample
        # for all samples, add s
        else:
            for i, spectra in enumerate(spectra_per_sample):
                final_spectra_lst[i].extend(spectra)
    final_spectra_lst = [list(set(spectra_lst)) for spectra_lst in final_spectra_lst]
    return final_spectra_lst



