"""
Transaction progress data processor.

Processes raw transaction progress data into an immutable tree structure,
separating data transformation from display concerns.
"""
from typing import Dict, List, Optional
from collections import defaultdict
from dataclasses import dataclass

from dateutil.parser import isoparse


@dataclass(frozen=True)
class ProcessedTask:
    """Immutable tree representation of a processed task."""
    task_id: str
    task_name: str
    duration: Optional[float]  # Duration in seconds (None if not finished)
    warnings: tuple[tuple[str, str], ...]  # Tuple of (warning_code, message)
    children: tuple['ProcessedTask', ...]  # Immutable children


def _duration_s(task: Dict) -> Optional[float]:
    """Calculate task duration in seconds. Return None if not finished."""
    if "start_time" not in task or "end_time" not in task:
        return None
    
    start = isoparse(task["start_time"])
    end = isoparse(task["end_time"])
    return (end - start).total_seconds()


def _build_graph(tasks: Dict) -> Dict:
    """Build parent-child relationship graph from tasks."""
    children = defaultdict(list)

    for tid, t in tasks.items():
        if "origin_id" in t:
            parent = t["origin_id"]
            children[parent].append(tid)

    return children


def _find_roots(tasks: Dict) -> list[str]:
    """Find root tasks (those with no parents)."""
    return [tid for tid in tasks if "origin_id" not in tasks[tid] or tasks[tid]["origin_id"] not in tasks]


def build_progress_tree(tasks: Dict) -> List[ProcessedTask]:
    """
    Build an immutable tree structure from raw task data.
    
    Args:
        tasks: Raw task data from transaction progress
        
    Returns:
        List of root ProcessedTask tree nodes
    """
    children = _build_graph(tasks)
    roots = _find_roots(tasks)
    
    # Build tree structure
    processed = []
    for root_id in roots:
        node = _build_task_node(root_id, tasks[root_id], children, tasks)
        if node:
            processed.append(node)
    
    return processed


def _build_task_node(
    task_id: str,
    task: Dict,
    children_map: Dict,
    all_tasks: Dict
) -> Optional[ProcessedTask]:
    """
    Recursively build a task tree node with its children.
    
    Args:
        task_id: The transaction task ID
        task: The task data
        children_map: Map of parent IDs to child IDs
        all_tasks: All tasks in the transaction
        
    Returns:
        ProcessedTask tree node or None if task should be filtered
    """
    # Extract raw task data
    task_name = task.get("task_name", task_id)
    duration = _duration_s(task)
    
    # Extract warnings
    warning_list = []
    if "warnings" in task and task["warnings"]:
        for warning_code, warning_data in task["warnings"].items():
            message = warning_data.get("message", "")
            warning_list.append((warning_code, message))
    
    # Process children
    child_nodes = []
    if task_id in children_map:
        child_list = children_map[task_id]
        for child_id in child_list:
            child_node = _build_task_node(
                child_id,
                all_tasks[child_id],
                children_map,
                all_tasks
            )
            if child_node:
                child_nodes.append(child_node)
    
    return ProcessedTask(
        task_id=task_id,
        task_name=task_name,
        duration=duration,
        warnings=tuple(warning_list),
        children=tuple(child_nodes)
    )
