#%% [markdown]
# # `create_variables_from_json`
#
# This function reads a JSON file and extracts data to set up various configuration variables. 
# The function primarily updates paths for data and image directories. 
# If no CSV filename is provided, the function searches the provided directory for the first CSV file it finds. 
#
# # `check_folder_for_csv`
#
# This function checks a given folder for the presence of a CSV file. 
# - If a CSV file is found, its file path is returned. 
# - If no CSV file is found, a `FileExistsError` is raised.
#
# # `convert_labview_to_metainfo`
#
# This function converts an input file generated by LabVIEW into a tab-separated values (TSV) file format. 
# It takes a raw data file and transforms it into a more digestible format for PyDIC. 
# The function also generates 'mock' force values based on the 'ElapsedTime' column.
#
# # `resample_dic_df`
#
# This function resamples the dataframe resulting from DIC (Digital Image Correlation) analysis, 
# based on a new time vector. 
# This can be used to obtain results at specific time points or to align results with another dataset.
#
# # `resample_ut`
#
# This function works similarly to `resample_dic_df`, but it's designed to resample the dataframe 
# of the IMADA testing machine results. It adjusts these results to match a new time vector.
#
# #TODO: Please note that the `convert_labview_to_metainfo` and `plot_synced_graph` functions could be 
# refactored to improve clarity and modularity. This can be done by splitting large functions into smaller ones, 
# which perform distinct tasks.
#%%
import json
import logging
import pathlib
from enum import Enum

import numpy as np
import pandas as pd
from matplotlib import pyplot as plt


class EnumInteropolation(Enum):
    """this is an Collection of values that interpolation can take.

    The problem is that the code is based on str, instead of integer values

    Returns:
        _type_: _description_
    """    
    RAW = 'raw'
    LINEAR = 'linear'
    CUBIC = 'cubic'
    SPLINE = 'spline'
    DEALUNEY = 'delauney'

    @classmethod
    def to_list(cls):
        # return cls._member_names_
        return list(map(lambda c: c.value, cls)) # with enum
        # return [value for name, value in vars(cls).items() if not name.startswith("__")]
        # return [cls.RAW, cls.LINEAR, cls.CUBIC, cls.SPLINE, cls.DEALUNEY]

class EnumStrainType(Enum):
    CAUCHY = 'cauchy'
    LOG = 'log'
    SECOND_ORDER = '2nd_order'

    @classmethod
    def to_list(cls):
        # return cls._member_names_
        return list(map(lambda c: c.value, cls))
        # return [cls.CAUCHY, cls.LOG, cls.SECOND_ORDER]

class EnumTrackingMethodType(Enum):
    #TOD O
    UNSTRUCTURED = 'unstructured_grid'
    DEEP_FLOW = 'deep_flow'
    LucasKanade  = 'Lucas-Kanade'

    @classmethod
    def to_list(cls):
        # return cls._member_names_
        return list(map(lambda c: c.value, cls))
        # return [cls.CAUCHY, cls.LOG, cls.SECOND_ORDER]


def create_variables_from_json(json_file_path:str):
    """this is an auxiliary function that automates the reading of the config file. 

    If the UTDATA_FNAME is not provided (or it is ""), then the program tries to search the TENSILEDATA_DIR for a csv. 

    Args:
        json_file_path (str): path to json file 

    Returns:
        dict: dictionary with analysis results
    """    
    with open(json_file_path, 'r') as f:
        json_data:dict = json.load(f)

    try:
        json_data["TENSILEDATA_DIR"] = pathlib.Path(json_data.get("TENSILEDATA_DIR",None))
    except:
        logging.info(f"There is no entry {'TENSILEDATA_DIR'}")
    
    if  json_data.get("UTDATA_FNAME", "") == "":
        # look for file name
        if (csvpath := next(json_data["TENSILEDATA_DIR"].glob("*.csv"), None)) is None:
            raise(FileExistsError("No .csv file present!"))
        else:
            print(f"Found file: {csvpath}")
            json_data["UTDATA"] = pathlib.Path(csvpath)
    else:      
        json_data["UTDATA"] = json_data["TENSILEDATA_DIR"] / json_data["UTDATA_FNAME"]
    json_data["IMG_DIR"] = pathlib.Path(json_data["IMG_DIR"])
    return json_data

def check_folder_for_csv(folder_path:pathlib.Path):
    """this is an auxiliary function checks a folder for a single csv  file

    Args:
        folder_path (_type_): _description_

    Returns:
        _type_: _description_
    """    
    if (csvpath := next(folder_path.glob("*.csv"), None)) is None:
        raise(FileExistsError("No .csv file present!"))
    else:
        print(f"Found file: {csvpath}")
        UTDATA = pathlib.Path(csvpath)
    return UTDATA

def convert_labview_to_metainfo(in_fname:pathlib.Path,out_fname:pathlib.Path, img_ext:str="png"):
    """coverts the output file from labview to the "meta-data.txt" required by pydic

    Args:
        in_fname (pathlib.Path): input filename
        out_fname (pathlib.Path): output filename 
        img_ext (str): Image file extension 
    """    
    dfcols = ['ImgNo', "Timestamp", 'ElapsedTime']
    df = pd.read_csv(in_fname, delimiter="\t", header=None, names=dfcols)

    df['filename'] = df.ImgNo.apply(lambda x: f"Cam_{x:05d}.{img_ext}")

    df = df.loc[:, ['filename', "ElapsedTime"]]
    # The following mocks up the force 
    df['force'] = df['ElapsedTime'].round(decimals=0)

    df.columns= ['file', 'time(s)', 'force(N)']

    df.to_csv(out_fname, index=False, sep='\t')


# %% [markdown]
# # Resampling
# ## obsolete attempt with pandas.resample
# The following is an failed attempt to resampling the dataframe 
# on sub second time scale. 
# 
# Issues:
# - I could not obtain meaningful values when I resampled
#%%
# index_td = pd.to_timedelta(df_dic['time_synced'], unit ="s")
# # index_td = pd.to_datetime(df_dic['time_synced'], unit ="s")
# df_dict = df_dic.set_index(index_td )
# df_dict.resample('100ms',origin=0).interpolate('linear')


def resample_dic_df(df_dic:pd.DataFrame,  ts:np.ndarray)->pd.DataFrame:
    """resamples the DIC analysis dataframe, on another time vector.

    Args:
        df_dic (pd.DataFrame): DIC Dataframe 
        ts (np.ndarray): new time vector. eg: np.arange(0,14,step=0.5).

    Returns:
        pd.DataFrame: new DataFrame with results 
    """
    dss = []
    for columnname in df_dic.iloc[:,:4]:

        interp_data = np.interp(ts, df_dic['time_synced'],df_dic[columnname])
        ds_new = pd.Series(interp_data, index = ts, name=columnname)
        dss.append(ds_new)
    res_df = pd.concat(dss,axis=1)
    return res_df 

def resample_ut(df_ut:pd.DataFrame,  ts:np.ndarray)->pd.DataFrame:
    """resamples the IMADA M testing machine results, on another time vector.

    Args:
        df_ut (pd.DataFrame): imada ut machine Dataframe (columms: [force_N, disp_mm, time_s])
        ts (np.ndarray): new time vector. eg: np.arange(0,14,step=0.5).

    Returns:
        pd.DataFrame: new DataFrame with results 
    """
    assert all([df_ut.columns[k]== v  for  k, v in enumerate(['force_N', 'disp_mm', 'time_s'])]), "Columns in input Df should be ['force_N', 'disp_mm', 'time_s']"
    dss = []
    for columnname in df_ut.iloc[:,:2]:
        logging.debug(columnname)
        interp_data = np.interp(ts, df_ut['time_s'],df_ut[columnname])
        ds_new = pd.Series(interp_data, index = ts, name=columnname)
        dss.append(ds_new)
    res_df = pd.concat(dss,axis=1)
    return res_df

