import os
import pathlib
from typing import Dict, List, Optional

import pandas as pd

from autorag.schema import Node
from autorag.utils.util import load_summary_file


def make_node_lines(node_line_dict: Dict) -> List[Node]:
    """
    This method makes a list of nodes from node line dictionary.
    :param node_line_dict: Node_line_dict loaded from yaml file, or get from user input.
    :return: List of Nodes inside this node line.
    """
    nodes = node_line_dict.get('nodes')
    if nodes is None:
        raise ValueError("Node line must have \'nodes\' key.")
    node_objects = list(map(lambda x: Node.from_dict(x), nodes))
    return node_objects


def run_node_line(nodes: List[Node],
                  node_line_dir: str,
                  previous_result: Optional[pd.DataFrame] = None):
    """
    Run the whole node line by running each node.

    :param nodes: A list of nodes.
    :param node_line_dir: This node line's directory.
    :param previous_result: A result of the previous node line.
        If None, it loads qa data from data/qa.parquet.
    :return: The final result of the node line.
    """
    if previous_result is None:
        project_dir = pathlib.PurePath(node_line_dir).parent.parent
        qa_path = os.path.join(project_dir, "data", "qa.parquet")
        if not os.path.exists(qa_path):
            raise ValueError(f"qa.parquet does not exist in {qa_path}.")
        previous_result = pd.read_parquet(qa_path)

    summary_lst = []
    for node in nodes:
        previous_result = node.run(previous_result, node_line_dir)
        node_summary_df = load_summary_file(os.path.join(node_line_dir, node.node_type, 'summary.csv'))
        best_node_row = node_summary_df.loc[node_summary_df['is_best']]
        summary_lst.append({
            'node_type': node.node_type,
            'best_module_filename': best_node_row['filename'].values[0],
            'best_module_name': best_node_row['module_name'].values[0],
            'best_module_params': best_node_row['module_params'].values[0],
            'best_execution_time': best_node_row['execution_time'].values[0],
        })
    pd.DataFrame(summary_lst).to_csv(os.path.join(node_line_dir, 'summary.csv'), index=False)
    return previous_result
