import os
from shutil import move as shutil_move

from pandas import read_csv, Series


# helper functions
def calculate_title_padding(subtitle: str) -> str:
    # this func helps with formatting logger messages
    title = '-'*50+'Fetching Sample Information'+'-'*50
    length = len(title)-len(subtitle)
    if length<=0:
        return '-'*40 + subtitle + '-'*40
    num: int = int(length/2)
    if length%2 == 0:
        return '-'*num + subtitle + '-'*num
    else:
        return '-'*num + subtitle + '-'*(num+1)
    

def csv_col_reader(*cols: str):
    # this decorator helps retrieve additional columns from the metadata csv file
    # cols: csv column names to be added to the returned tuple
    def inner(func):

        def wrapper(metadata_path: str, raw_dir: str):
            if len(cols) != 0:
                df = read_csv(metadata_path)
                added_info: list = [df.get(col) for col in cols]    # .get() can handle cases where the column doesnt exist
                added_info: list = [df[col] if col in df.columns else Series([None] * len(df)) for col in cols]     # return an iterable version of None if None
                csv_info, path_info = func(metadata_path, raw_dir)
                emdb_ids, pdbs, resolutions = csv_info
                csv_info_with_added_cols = (emdb_ids, pdbs, resolutions, *added_info)
                return csv_info_with_added_cols, path_info
            else:
                return func(metadata_path, raw_dir)
        return wrapper
    
    return inner


def read_csv_info(csv_path, raw_dir):
    df = read_csv(csv_path)
    emdbs, pdbs = df["emdb_id"], df["fitted_pdbs"]
    resolutions = df["resolution"].astype(str)
    emdb_ids = [emdb.split("-")[1] for emdb in emdbs]
    folders = [
        f"{emdb}_re_{resolution}"
        for emdb, resolution in zip(emdbs, resolutions)
    ]
    raw_maps = [f"emd_{emdb_id}.map" for emdb_id in emdb_ids]
    models = [f"{pdb}.cif" for pdb in pdbs]

    raw_map_paths = [os.path.join(raw_dir, folder, raw_map) for folder, raw_map in zip(folders, raw_maps)]
    model_paths = [os.path.join(raw_dir, folder, model) for folder, model in zip(folders, models)]
    normalized_map_paths = [os.path.join(raw_dir, folder, f"{os.path.splitext(os.path.basename(raw_map_path))[0]}_normalized.mrc")\
                             for folder, raw_map_path in zip(folders, raw_map_paths)]

    csv_info = (emdb_ids, pdbs, resolutions)
    path_info = (raw_map_paths, model_paths, normalized_map_paths)
    return csv_info, path_info


def move_log_file(start: str,
                  destination: str
                  ):
    # this function moves the log file generated by the program to a specified directory
    # start: the path to the log file
    # destination: the path to the destination directory
    if not os.path.exists(destination):
        os.path.mkdir(destination)
    shutil_move(start, destination)
