import os
import re
import pickle
import pandas as pd
import numpy as np
from tqdm import tqdm
import contextlib
import argparse

from dynotears import from_pandas_dynamic as from_pandas_dynamic
from dynotears_and import from_pandas_dynamic as from_pandas_dynamic_and
from dynotears_and_init import from_pandas_dynamic as from_pandas_dynamic_and_initdata
from dynotears_multiply import from_pandas_dynamic as from_pandas_dynamic_multiply
from dynotears_multiply_init import from_pandas_dynamic as from_pandas_dynamic_multiply_initdata
from dynotears_randomlag import from_pandas_dynamic as from_pandas_dynamic_randomlag
from utils import get_solve_matrix, get_gt_matrix, get_result_matrix, read_markdown_table

def save_weights_to_csv(w_matrix, a_matrix, p_orders, d_vars, filename):
    df_w = pd.DataFrame(w_matrix, columns=[f'dest_{j}' for j in range(d_vars)])
    df_w['matrix_type'] = 'W'
    df_w['lag'] = 0
    df_w['source_node'] = range(d_vars)

    df_a = pd.DataFrame(a_matrix, columns=[f'dest_{j}' for j in range(d_vars)])
    df_a['matrix_type'] = 'A'
    lags = np.repeat(np.arange(1, p_orders + 1), d_vars)
    source_nodes = np.tile(np.arange(d_vars), p_orders)
    df_a['lag'] = lags
    df_a['source_node'] = source_nodes

    df_combined = pd.concat([df_w, df_a], ignore_index=True)

    id_cols = ['matrix_type', 'lag', 'source_node']
    weight_cols = [f'dest_{j}' for j in range(d_vars)]
    df_combined = df_combined[id_cols + weight_cols]

    df_combined.to_csv(filename, index=False, encoding='utf-8-sig')
    print(f"  Weights saved to '{os.path.basename(filename)}'")

def get_result_matrix_df(result_matrix):
    index = [f"timeseries_{i}" for i in range(result_matrix.shape[0] - 2)]
    return pd.DataFrame(result_matrix, index=["timeseries", "total"] + index, columns=["accuracy", "recall", "f1", "shd", "edge_loss", "edge_recovery", "weak_correct_edge_num", "weak_edge_num"])

def merge_results(data_dir: str, repeat_num: int = 6):
    try:
        exps_dirs = sorted([
            d for d in os.listdir(data_dir) if
            os.path.isdir(os.path.join(data_dir, d)) and d.startswith('exist_edges_prob_')
        ])
    except FileNotFoundError:
        print(f"  Error: Data directory not found: {data_dir}")
        return
    except Exception as e:
        print(f"  Error listing directories in {data_dir}: {e}")
        return
    if not exps_dirs:
        print(f"  Info: No 'exist_edges_prob_' subdirectories found in {data_dir} for merging.")
        return

    print(f"Merging results (calculating diffs) in {os.path.basename(data_dir)}...")
    for exp_dir in exps_dirs:
        full_exp_path = os.path.join(data_dir, exp_dir)
        print(f"  Processing experiment: {exp_dir}")

        diff_matrix_list = []
        mean_matrix_list = []
        valid_runs_processed = 0

        for i in range(repeat_num):
            baseline_result_matrix = None
            constrained_matrix = None

            baseline_file = os.path.join(full_exp_path, f"result_baseline_{i}.md")
            if os.path.exists(baseline_file):
                try:
                    baseline_df = read_markdown_table(baseline_file)
                    if baseline_df.shape[1] > 1:
                        baseline_result_matrix = baseline_df.to_numpy()[:, 1:].astype(float)
                        mean_matrix_list.append(baseline_result_matrix)
                    else:
                         print(f"  Warning: Baseline file {baseline_file} has too few columns. Skipping run {i}.")
                         continue
                except pd.errors.EmptyDataError:
                     print(f"  Warning: Baseline file {baseline_file} is empty. Skipping run {i}.")
                     continue
                except Exception as e:
                    print(f"  Warning: Could not read/process baseline {baseline_file}: {e}. Skipping run {i}.")
                    continue
            else:
                continue

            constrained_result_file = os.path.join(full_exp_path, f"result_constrained_{i}.md")
            if os.path.exists(constrained_result_file):
                try:
                    constrained_df = read_markdown_table(constrained_result_file)
                    if constrained_df.shape[1] > 1:
                        constrained_matrix = constrained_df.to_numpy()[:, 1:].astype(float)
                    else:
                         print(f"  Warning: Constrained file {constrained_result_file} has too few columns. Skipping run {i}.")
                         continue
                except pd.errors.EmptyDataError:
                     print(f"  Warning: Constrained file {constrained_result_file} is empty. Skipping run {i}.")
                     continue
                except Exception as e:
                    print(f"  Warning: Could not read/process constrained {constrained_result_file}: {e}. Skipping run {i}.")
                    continue
            else:
                continue

            if baseline_result_matrix is not None and constrained_matrix is not None:
                if baseline_result_matrix.shape == constrained_matrix.shape:
                    diff = constrained_matrix - baseline_result_matrix
                    diff_matrix_list.append(diff)
                    valid_runs_processed += 1
                else:
                    print(f"  Warning: Shape mismatch for run {i}. Baseline: {baseline_result_matrix.shape}, Constrained: {constrained_matrix.shape}. Skipping.")

        if mean_matrix_list:
            print(f"    Calculating average mean from {len(mean_matrix_list)} valid runs for {exp_dir}...")
            mean_mean_matrix = np.mean(np.array(mean_matrix_list), axis=0)

            try:
                 mean_matrix_df = get_result_matrix_df(mean_mean_matrix)
                 mean_output_file = os.path.join(full_exp_path, "result_constrained_mean.md")
                 mean_matrix_df.to_markdown(mean_output_file)
                 print(f"    Saved average mean to {mean_output_file}")
            except Exception as e:
                 print(f"  Error: Failed to convert/save average mean for {exp_dir}: {e}")
        else:
            print(f"    Warning: No valid runs found to calculate mean for {exp_dir}.")
        
        if diff_matrix_list:
            print(f"    Calculating average difference from {len(diff_matrix_list)} valid runs for {exp_dir}...")
            mean_diff_matrix = np.mean(np.array(diff_matrix_list), axis=0)

            try:
                 diff_matrix_df = get_result_matrix_df(mean_diff_matrix)
                 diff_output_file = os.path.join(full_exp_path, "result_constrained_diff.md")
                 diff_matrix_df.to_markdown(diff_output_file)
                 print(f"    Saved average difference to {diff_output_file}")
            except Exception as e:
                 print(f"  Error: Failed to convert/save average difference for {exp_dir}: {e}")
        else:
            print(f"    Warning: No valid runs found to calculate difference for {exp_dir}.")

    print("Merging process finished.")

def consolidate_results(data_dir: str, output_filename: str = "results_consolidated.md"):
    print(f"  Starting consolidation for directory: {os.path.basename(data_dir)}")
    all_results_dfs = []
    base_results_dfs = []
    exps_dirs = sorted([
        d for d in os.listdir(data_dir) if
        os.path.isdir(os.path.join(data_dir, d)) and d.startswith('exist_edges_prob_')
    ])

    if not exps_dirs:
        print(f"  Info: No 'exist_edges_prob_' subdirectories found in {os.path.basename(data_dir)} for consolidation.")

    for exp_dir in exps_dirs:
        exp_path = os.path.join(data_dir, exp_dir)

        match = re.search(r'exist_edges_prob_(\d+(\.\d+)?)', exp_dir)
        if not match:
            continue
        prob_value = float(match.group(1))
        
        baseline_file_path = os.path.join(exp_path, f"result_constrained_mean.md")
        baseline_df = read_markdown_table(baseline_file_path)
        if not baseline_df.empty:
            baseline_df.insert(0, 'edge_prior_prob', prob_value)
            base_results_dfs.append(baseline_df)
        
        diff_file_path = os.path.join(exp_path, "result_constrained_diff.md")
        diff_df = read_markdown_table(diff_file_path)
        if not diff_df.empty:
            diff_df.insert(0, 'edge_prior_prob', prob_value)
            all_results_dfs.append(diff_df)
            
    base_combined_df = pd.concat(base_results_dfs, ignore_index=True)
    all_combined_df = pd.concat(all_results_dfs, ignore_index=True)

    base_output_path = os.path.join(data_dir, f'base_{output_filename}')
    output_format = output_filename.split('.')[-1].lower()
    if output_format == "csv":
        base_combined_df.to_csv(base_output_path, index=False, float_format='%.4f')
        print(f"  Consolidation successful. Saved to CSV: base_{output_filename}")
    elif output_format == "md":
        base_combined_df.to_markdown(base_output_path, index=False, floatfmt=".4f")
        print(f"  Consolidation successful. Saved to Markdown: base_{output_filename}")
    else:
        print(f"  Warning: Unsupported output file format 'base_{output_filename}'. Please use .csv or .md. File not saved.")
        
    all_output_path = os.path.join(data_dir, f'all_{output_filename}')
    output_format = output_filename.split('.')[-1].lower()
    if output_format == "csv":
        all_combined_df.to_csv(all_output_path, index=False, float_format='%.4f')
        print(f"  Consolidation successful. Saved to CSV: all_{output_filename}")
    elif output_format == "md":
        all_combined_df.to_markdown(all_output_path, index=False, floatfmt=".4f")
        print(f"  Consolidation successful. Saved to Markdown: all_{output_filename}")
    else:
        print(f"  Warning: Unsupported output file format 'all_{output_filename}'. Please use .csv or .md. File not saved.")
        
def aggregate_all_consolidated(
    data_path: str,
    data_info: str,
    name: str,
    consolidated_filename: str,
    final_output_filename: str = "final_aggregated_summary.csv"
):
    print(f"\nStarting aggregation of all consolidated files in: {os.path.basename(data_path)}")
    print(f"Looking for files named: {consolidated_filename}")

    all_repeat_dfs = []
    base_repeat_dfs = []

    repeat_dirs = sorted([
        d for d in os.listdir(data_path) if
        os.path.isdir(os.path.join(data_path, d)) and d.startswith('repeat')
    ])

    if not repeat_dirs:
        print(f"Error: No 'repeatX' subdirectories found in {data_path}. Cannot aggregate.")
        return
    for dir_name in repeat_dirs:
        full_dir_path = os.path.join(data_path, dir_name)
        base_consolidated_file_path = os.path.join(full_dir_path, f'base_{consolidated_filename}')
        all_consolidated_file_path = os.path.join(full_dir_path, f'all_{consolidated_filename}')

        match = re.search(r'repeat(\d+)', dir_name)
        if not match:
            continue
        dataset_index = int(match.group(1))
        
        if os.path.exists(base_consolidated_file_path):
            try:
                if consolidated_filename.endswith(".csv"):
                    df = pd.read_csv(base_consolidated_file_path)
                elif consolidated_filename.endswith(".md"):
                    df = read_markdown_table(base_consolidated_file_path)
                else:
                    print(f"  Warning: Unsupported file type {consolidated_filename}, skipping.")
                    continue
                if not df.empty:
                    df.insert(0, 'dataset_index', dataset_index)
                    base_repeat_dfs.append(df)
            except Exception as e:
                print(f"  Warning: Failed to read file {base_consolidated_file_path}: {e}")
        
        
        if os.path.exists(all_consolidated_file_path):
            try:
                if consolidated_filename.endswith(".csv"):
                    df = pd.read_csv(all_consolidated_file_path)
                elif consolidated_filename.endswith(".md"):
                    df = read_markdown_table(all_consolidated_file_path)
                else:
                    print(f"  Warning: Unsupported file type {consolidated_filename}, skipping.")
                    continue
                if not df.empty:
                    df.insert(0, 'dataset_index', dataset_index)
                    all_repeat_dfs.append(df)
            except Exception as e:
                print(f"  Warning: Failed to read file {all_consolidated_file_path}: {e}")

    base_final_combined_df = pd.concat(base_repeat_dfs, ignore_index=True)
    print(f"Successfully combined data from {len(base_repeat_dfs)} repeat directories.")
    all_final_combined_df = pd.concat(all_repeat_dfs, ignore_index=True)
    print(f"Successfully combined data from {len(all_repeat_dfs)} repeat directories.")

    if not os.path.exists(os.path.join('result/result_prior', name)):
        os.mkdir(os.path.join('result/result_prior', name))

    if not os.path.exists(os.path.join('result/result_prior', name, data_info)):
        os.mkdir(os.path.join('result/result_prior', name, data_info))
        
    base_final_output_path = os.path.join('result/result_prior', name, data_info, f'base_{final_output_filename}')
    
    output_format = final_output_filename.split('.')[-1].lower()
    if output_format == "csv":
        base_final_combined_df.to_csv(base_final_output_path, index=False, float_format='%.4f')
    elif output_format == "md":
        base_final_combined_df.to_markdown(base_final_output_path, index=False, floatfmt=".4f")
    else:
        print(f"Warning: Unsupported final output format '{output_format}'. Saving as CSV.")
        base_final_output_path = os.path.join('result/result_prior', name, data_info, "base_final_aggregated_summary.csv")
        base_final_combined_df.to_csv(base_final_output_path, index=False, float_format='%.4f')
    
    all_final_output_path = os.path.join('result/result_prior', name, data_info, f'all_{final_output_filename}')
    
    output_format = final_output_filename.split('.')[-1].lower()
    if output_format == "csv":
        all_final_combined_df.to_csv(all_final_output_path, index=False, float_format='%.4f')
    elif output_format == "md":
        all_final_combined_df.to_markdown(all_final_output_path, index=False, floatfmt=".4f")
    else:
        print(f"Warning: Unsupported final output format '{output_format}'. Saving as CSV.")
        all_final_output_path = os.path.join('result/result_prior', name, data_info, "all_final_aggregated_summary.csv")
        all_final_combined_df.to_csv(all_final_output_path, index=False, float_format='%.4f')

    print(f"Successfully saved final aggregated results to: {all_final_output_path}")

def solve(data_dir: str, args, exist_edges_prob: float = 0.1, repeat_num: int = 6):
    data = pickle.load(open(os.path.join(data_dir, "data.pkl"), "rb"))
    links_infos = pickle.load(open(os.path.join(data_dir, "links_infos.pkl"), "rb"))
    p = int(re.findall(r'porders(\d+)', data_dir)[0])
    d_vars = data.shape[1]
    gt = get_gt_matrix(links_infos=links_infos, p=p)

    gt_2D = gt.copy().reshape((p + 1) * d_vars, d_vars)
    gt_filename = os.path.join(data_dir, "ground_truth.csv")
    pd.DataFrame(gt_2D).to_csv(gt_filename, index=False, header=False, encoding='utf-8-sig')

    constrained_dir = os.path.join(data_dir, f"exist_edges_prob_{exist_edges_prob}")
    os.makedirs(constrained_dir, exist_ok=True)

    print(f"  Solving true baseline for {os.path.basename(data_dir)} for comparison...")
    sm_baseline, eloss_baseline, (w_est_baseline, a_est_baseline) = from_pandas_dynamic(
        pd.DataFrame(data), p=p, lambda_e=0.1, w_threshold=0.1, exist_edges_mask=None
    )
    solve_baseline_structure = get_solve_matrix(sm=sm_baseline, p=p, d_vars=d_vars)
    
    empty_mask = np.zeros((d_vars, d_vars))
    result_matrix_baseline_df = get_result_matrix_df(
        get_result_matrix(solve_baseline_structure, gt, eloss_baseline, empty_mask, w_est_baseline, a_est_baseline, 0.1, p, d_vars)
    )
    print(f"  True baseline solved. Metrics will be used for comparison in {repeat_num} runs.")

    gt_collapsed = np.any(gt, axis=0)
    all_gt_edges_rows, all_gt_edges_cols = np.where(gt_collapsed)
    all_gt_edges_indices = list(zip(all_gt_edges_rows, all_gt_edges_cols))
    num_possible_edges = len(all_gt_edges_indices)

    if num_possible_edges == 0:
        print(f"  Warning: No potential edges found in GT for {os.path.basename(data_dir)}. Skipping constrained solve for prob {exist_edges_prob}.")
        return

    num_edges_to_select = int(np.ceil(exist_edges_prob * num_possible_edges))
    if num_edges_to_select > num_possible_edges:
        print(f"  Warning: Requested more prior edges ({num_edges_to_select}) than possible ({num_possible_edges}). Using all possible edges.")
        num_edges_to_select = num_possible_edges

    alg_mapping = {
        'and_init0': from_pandas_dynamic_and,
        'and_initdata': from_pandas_dynamic_and_initdata,
        'multiply_init0': from_pandas_dynamic_multiply,
        'multiply_initdata': from_pandas_dynamic_multiply_initdata,
        'lag_0': from_pandas_dynamic_randomlag,
        'lag_10': from_pandas_dynamic_randomlag,
        'lag_30': from_pandas_dynamic_randomlag,
        'lag_50': from_pandas_dynamic_randomlag,
        'lag_80': from_pandas_dynamic_randomlag
    }
    selected_alg = alg_mapping[args.algorithm]

    for i in tqdm(range(repeat_num), desc=f"    Runs (p={exist_edges_prob})", unit="run", leave=False):
        result_matrix_baseline_df.to_markdown(os.path.join(constrained_dir, f"result_baseline_{i}.md"))
        weights_baseline_filename = os.path.join(constrained_dir, f"baseline_weights_{i}.csv")
        save_weights_to_csv(w_est_baseline, a_est_baseline, p, d_vars, weights_baseline_filename)

        rng = np.random.default_rng(seed=i)
        exist_edges_mask = np.zeros((d_vars, d_vars))

        if num_edges_to_select > 0:
            indices_to_sample = rng.choice(len(all_gt_edges_indices), size=num_edges_to_select, replace=False)
            final_selected_edges = [all_gt_edges_indices[idx] for idx in indices_to_sample]

            for r, c in final_selected_edges:
                exist_edges_mask[r, c] = 1

        mask_filename_csv = os.path.join(constrained_dir, f"exist_edges_mask_{i}.csv")
        pd.DataFrame(exist_edges_mask).to_csv(mask_filename_csv, index=False, header=False, encoding='utf-8-sig')

        random_mask = np.zeros((p + 1, d_vars, d_vars), dtype=int)

        incorrect_ratio = int(args.algorithm.split('_')[1]) / 100.0
        
        prior_edge_indices = np.where(exist_edges_mask == 1)
        all_prior_edges = list(zip(prior_edge_indices[0], prior_edge_indices[1]))
        total_edges = len(all_prior_edges)
        
        import math
        target_incorrect_prior_count = math.ceil(total_edges * incorrect_ratio)
        target_incorrect_prior_count = int(target_incorrect_prior_count)
        
        edges_with_incorrect_lags = []
        for m, j in all_prior_edges:
            if np.sum(gt[:, m, j]) < (p + 1):
                edges_with_incorrect_lags.append((m, j))

        allocated_incorrect_count = 0
        used_edges = set()

        if target_incorrect_prior_count > 0 and edges_with_incorrect_lags:
            shuffled_edges = list(edges_with_incorrect_lags)
            rng.shuffle(shuffled_edges)
            
            for m, j in shuffled_edges:
                if allocated_incorrect_count >= target_incorrect_prior_count:
                    break
                
                true_lags_set = set(np.where(gt[:, m, j] == 1)[0])
                all_possible_lags_set = set(range(p + 1))
                incorrect_lags = list(all_possible_lags_set - true_lags_set)
                
                if incorrect_lags:
                    lag_to_set = rng.choice(incorrect_lags)
                    random_mask[lag_to_set, m, j] = 1
                    allocated_incorrect_count += 1
                    used_edges.add((m, j))

            if allocated_incorrect_count < target_incorrect_prior_count:
                available_incorrect_slots = []
                for m, j in edges_with_incorrect_lags:
                    true_lags_set = set(np.where(gt[:, m, j] == 1)[0])
                    all_possible_lags_set = set(range(p + 1))
                    incorrect_lags = list(all_possible_lags_set - true_lags_set)
                    
                    for lag in incorrect_lags:
                        if random_mask[lag, m, j] == 0:
                            available_incorrect_slots.append((lag, m, j))

                remaining_needed = target_incorrect_prior_count - allocated_incorrect_count
                num_to_allocate_extra = min(remaining_needed, len(available_incorrect_slots))
                
                if num_to_allocate_extra > 0:
                    slots_to_fill_indices = rng.choice(len(available_incorrect_slots), size=num_to_allocate_extra, replace=False)
                    slots_to_fill = [available_incorrect_slots[idx] for idx in slots_to_fill_indices]
                    
                    for lag, m, j in slots_to_fill:
                        random_mask[lag, m, j] = 1
                        allocated_incorrect_count += 1
                        used_edges.add((m, j))

        target_correct_prior_count = total_edges - np.sum(random_mask)
        available_edges_for_correct = [edge for edge in all_prior_edges if edge not in used_edges]
        num_correct_to_allocate = min(target_correct_prior_count, len(available_edges_for_correct))

        if num_correct_to_allocate > 0:
            edges_for_correct_allocation_indices = rng.choice(len(available_edges_for_correct), size=num_correct_to_allocate, replace=False)
            edges_for_correct_allocation = [available_edges_for_correct[idx] for idx in edges_for_correct_allocation_indices]

            for m, j in edges_for_correct_allocation:
                true_lags_for_edge = np.where(gt[:, m, j] == 1)[0]
                if len(true_lags_for_edge) > 0:
                    lag_to_set = rng.choice(true_lags_for_edge)
                    if random_mask[lag_to_set, m, j] == 0:
                        random_mask[lag_to_set, m, j] = 1
                        used_edges.add((m, j))

        common_params = {
            'p': p,
            'w_threshold': 0.1,
            'lambda_e': 0.5,
        }
        
        if 'multiply' in args.algorithm:
            common_params['lambda_p'] = 10
            common_params['exist_edges_mask'] = exist_edges_mask
        elif 'and' in args.algorithm:
            common_params['exist_edges_mask'] = exist_edges_mask
        elif 'lag' in args.algorithm:
            common_params['exist_edges_mask'] = random_mask

        sm_constrained, eloss_constrained, (w_est_constrained, a_est_constrained) = selected_alg(pd.DataFrame(data), **common_params)
        
        weights_constrained_filename = os.path.join(constrained_dir, f"constrained_multiply_weights_{i}.csv")
        save_weights_to_csv(w_est_constrained, a_est_constrained, p, d_vars, weights_constrained_filename)
        solve_constrained = get_solve_matrix(sm=sm_constrained, p=p, d_vars=d_vars)
        result_matrix_constrained = get_result_matrix_df(
            get_result_matrix(solve_constrained, gt, eloss_constrained, exist_edges_mask, w_est_constrained, a_est_constrained, 0.1, p, d_vars)
        )
        result_filename = os.path.join(constrained_dir, f"result_constrained_{i}.md")
        result_matrix_constrained.to_markdown(result_filename)

    print(f"  Constrained solving with priors (prob={exist_edges_prob}) finished for all {repeat_num} runs.")


if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Run causal discovery experiments and aggregate results.")
    parser.add_argument("--data_root", type=str, default="simulated_data", help="Root directory containing simulation parameter folders.")
    parser.add_argument("--repeat_num", type=int, default=6, help="Number of random mask repetitions for constrained solving.")
    parser.add_argument('--node_num', type=int, default=10, help="Number of nodes in the simulation.")
    parser.add_argument('--edge_num', type=int, default=15, help="Number of edges in the simulation.")
    parser.add_argument('--p_orders', type=int, default=3, help="Number of time lags (p orders).")
    parser.add_argument('--T', type=int, default=500, help="Length of the time series.")
    parser.add_argument("--noises_type", type=str, default="gauss")
    parser.add_argument('--edge_probs', nargs='+', type=float, default=[0.8], help='List of edge prior probabilities to test.')
    parser.add_argument('--algorithm', type=str, default='and_init0')
    parser.add_argument('--consolidated_format', type=str, default="csv", choices=['csv', 'md'], help='Format for the consolidated results file per repeat.')
    parser.add_argument('--final_format', type=str, default="csv", choices=['csv', 'md'], help='Format for the final aggregated summary file.')
    args = parser.parse_args()
    np.random.seed(42)

    data_info=f'node{str(args.node_num).zfill(3)}_edge{str(args.edge_num).zfill(3)}_porders{str(args.p_orders).zfill(1)}_T{str(args.T).zfill(4)}_noise{args.noises_type}'
    data_path = os.path.join(args.data_root, data_info)
    repeat_dirs = sorted([
            d for d in os.listdir(data_path) if
            os.path.isdir(os.path.join(data_path, d)) and d.startswith('repeat')
        ])

    for data_dir_basename in repeat_dirs:
        data_dir_path = os.path.join(data_path, data_dir_basename)
        print(f"\nProcessing repeat directory: {data_dir_basename}")

        for edge_prob in args.edge_probs:
            solve(data_dir_path, args, exist_edges_prob=edge_prob, repeat_num = args.repeat_num)
            
        merge_results(data_dir_path, repeat_num = args.repeat_num)

        output_file = f"results_consolidated.csv"
        consolidate_results(data_dir_path, output_filename=output_file)

    consolidated_filename = f"results_consolidated.csv"
    final_output_filename = f"final_aggregated_summary.csv"
    aggregate_all_consolidated(
        data_path=data_path,
        data_info=data_info,
        name=args.algorithm,
        consolidated_filename=consolidated_filename,
        final_output_filename=final_output_filename
    )
    print("\nScript finished.")