class PipelineNode:
    def __init__(self, name, partial_sequence=""):
        self.name = name
        self.children = {}
        self.score_sum = 0
        self.score_count = 0
        self.partial_sequence = partial_sequence

    def add_child(self, component):
        new_partial_sequence = self.partial_sequence + component if self.partial_sequence else component
        if component not in self.children:
            self.children[component] = PipelineNode(component, new_partial_sequence)
        return self.children[component]

    def update_score(self, score):
        self.score_sum += score
        self.score_count += 1

    def get_average_score(self):
        return self.score_sum / self.score_count if self.score_count > 0 else 0
    
    def is_terminal(self):
        return len(self.children) == 0

class PipelineNameTree:
    def __init__(self):
        self.root = PipelineNode("")

    @staticmethod
    def parse_pipeline_name(pipeline_name, component_names):
        component_positions = []
        for component in component_names:
            position = pipeline_name.find(component)
            if position != -1:
                component_positions.append((position, component))
        component_positions.sort()
        ordered_components = [comp for _, comp in component_positions]
        return ordered_components

    def build_tree(self, pipelines, scores, component_names):
        for pipeline, score in zip(pipelines, scores):
            components = self.parse_pipeline_name(pipeline, component_names)
            current_node = self.root
            for component in components:
                current_node = current_node.add_child(component)
            current_node.update_score(score)

    def compute_average_scores(self, node=None):
        if node is None:
            node = self.root

        for child in node.children.values():
            self.compute_average_scores(child)
            node.update_score(child.get_average_score())

        if node.name != "":
            node.score_sum = node.get_average_score()  # Update sum to average for non-root nodes

    def print_tree(self, node=None, depth=0):
        if node is None:
            node = self.root

        indent = "  " * depth
        if node.is_terminal():
            print(f"{indent}{node.name}: Score = {node.get_average_score():.4f}, Partial Sequence = {node.partial_sequence}")
        else:
            print(f"{indent}{node.name}: Avg Score = {node.get_average_score():.4f}")

        for child in node.children.values():
            self.print_tree(child, depth + 1)