#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
將 (method_name → sub_method_name) 的關係轉成一棵樹，
然後把所有節點依「深度」分組：
    depth = 0   → 完全沒有子節點的葉子
    depth = 1   → 子節點全部是 depth=0 的節點
    …
最深的 depth 為 root（可能有多個）。
"""

import json
from collections import defaultdict, deque
from pathlib import Path
from typing import Dict, List, Set, Tuple

from pilot.base.file_operation import read_json_file_lines, write_file_line
from pilot.job.impl.base_job import BaseJob


class MakeMergeOrderBaseJob(BaseJob):
    output_file_path = ''
    # --------------------------------------------------------------
    # 1️⃣ 把 parent‑>child 建成圖
    # --------------------------------------------------------------
    @staticmethod
    def build_graph(pairs: List[Dict[str, str]]) -> Dict[str, Set[str]]:
        """回傳 adjacency list，並把只出現在子欄位的節點也加入（它們是葉子）。"""
        graph = defaultdict(set)          # parent -> {child,…}
        children: Set[str] = set()

        for p in pairs:
            parent, child = p["method_name"], p["sub_method_name"]
            graph[parent].add(child)
            children.add(child)

        # 把只當過「子」卻沒出現在 key 的節點補進 graph（成為 leaf）
        for leaf in children:
            if leaf not in graph:
                graph[leaf] = set()

        return dict(graph)


    # --------------------------------------------------------------
    # 2️⃣ 拓撲排序（保證父在前、子在後）
    # --------------------------------------------------------------
    @staticmethod
    def topological_sort(graph: Dict[str, Set[str]]) -> List[str]:
        indeg = defaultdict(int)
        for p, childs in graph.items():
            for c in childs:
                indeg[c] += 1

        q = deque([n for n in graph if indeg[n] == 0])
        order: List[str] = []

        while q:
            u = q.popleft()
            order.append(u)
            for v in graph[u]:
                indeg[v] -= 1
                if indeg[v] == 0:
                    q.append(v)

        # 若有孤立節點（只在子集合裡），補上
        all_nodes = set(graph) | {c for cs in graph.values() for c in cs}
        missing = all_nodes - set(order)
        order.extend(missing)

        return order


    # --------------------------------------------------------------
    # 3️⃣ 計算每個節點的 depth（leaf = 0）
    # --------------------------------------------------------------
    def compute_depths(self, graph: Dict[str, Set[str]]) -> Dict[str, int]:
        order = self.topological_sort(graph)          # 父 → 子
        depth: Dict[str, int] = {}

        for node in reversed(order):              # 從葉子往上算
            childs = graph[node]
            if not childs:                        # 沒有子節點 → leaf
                depth[node] = 0
            else:
                depth[node] = 1 + max(depth[ch] for ch in childs)

        return depth


    # --------------------------------------------------------------
    # 4️⃣ 按深度收集節點
    # --------------------------------------------------------------
    @staticmethod
    def group_by_depth(depth: Dict[str, int]) -> Tuple[Dict[int, List[str]], int]:
        groups: Dict[int, List[str]] = defaultdict(list)
        max_depth = 0
        for node, d in depth.items():
            groups[d].append(node)
            if d > max_depth:
                max_depth = d
        return dict(groups), max_depth

    def run(self):

        pairs = read_json_file_lines(self.file_path)

        graph = self.build_graph(pairs)

        depths = self.compute_depths(graph)

        groups, max_depth = self.group_by_depth(depths)

        _order_content = []
        for d in range(max_depth + 1):
            for node in sorted(groups.get(d, [])):
                if d > 0:
                    _order_content.append(node)

        output_file = Path(self.file_path).with_suffix('.txt')
        out_content = '\n'.join(_order_content) + '\n'
        write_file_line(output_file, out_content)

        super().run()

        self.output_file_path = output_file
