"""Helper module to convert sessions into tree structures."""
import uuid
from typing import Any


def convert_session_to_tree(
    session_path: list[str],
    tree_snapshot: dict[str, Any],
    custom_steps: list[dict[str, Any]],
    decisions: list[dict[str, Any]]
) -> dict[str, Any]:
    """Convert a session's path and custom steps into a linear tree structure.

    Creates a linear decision tree that represents the path taken through the
    original tree, including any custom steps inserted during the session.

    Args:
        session_path: List of node IDs representing the path taken
        tree_snapshot: Original tree structure (for node details)
        custom_steps: Custom steps inserted during session
        decisions: Decision records with answers and notes

    Returns:
        Tree structure dict representing the linear path
    """
    if not session_path:
        # Return minimal valid tree if no path taken
        return {
            "id": str(uuid.uuid4()),
            "type": "solution",
            "title": "Session had no recorded path",
            "children": []
        }

    # Build a map of custom steps by their ID
    custom_steps_map = {}
    for step in custom_steps:
        if "id" in step:
            custom_steps_map[step["id"]] = step

    # Build a map of decisions by node_id for quick lookup
    decisions_map = {}
    for decision in decisions:
        if "node_id" in decision:
            decisions_map[decision["node_id"]] = decision

    # Build the linear tree structure
    root_node = None
    current_node = None

    for i, node_id in enumerate(session_path):
        # Check if this is a custom step
        if node_id in custom_steps_map:
            step = custom_steps_map[node_id]
            new_node = _create_node_from_custom_step(step, node_id)
        else:
            # Find node in original tree
            original_node = _find_node_in_tree(tree_snapshot, node_id)
            if original_node:
                new_node = _create_node_from_original(original_node, decisions_map.get(node_id))
            else:
                # Node not found, create a placeholder
                new_node = {
                    "id": node_id,
                    "type": "action",
                    "title": f"Step from original tree (node {node_id})",
                    "children": []
                }

        # Add notes from decision if available
        decision = decisions_map.get(node_id)
        if decision and decision.get("notes"):
            new_node["notes"] = decision["notes"]

        # Build the chain
        if root_node is None:
            root_node = new_node
            current_node = root_node
        else:
            current_node["children"] = [new_node]
            current_node = new_node

    return root_node


def _find_node_in_tree(tree: dict[str, Any], node_id: str) -> dict[str, Any] | None:
    """Recursively find a node in the tree structure by ID.

    Args:
        tree: Tree structure dict
        node_id: Node ID to find

    Returns:
        Node dict if found, None otherwise
    """
    if tree.get("id") == node_id:
        return tree

    for child in tree.get("children", []):
        result = _find_node_in_tree(child, node_id)
        if result:
            return result

    return None


def _create_node_from_original(
    original_node: dict[str, Any],
    decision: dict[str, Any] | None = None
) -> dict[str, Any]:
    """Create a new node based on an original tree node.

    Args:
        original_node: Original node from tree
        decision: Decision record for this node (optional)

    Returns:
        New node dict for the linear tree
    """
    node_type = original_node.get("type", "action")
    new_node = {
        "id": str(uuid.uuid4()),  # Generate new ID for the saved tree
        "type": node_type,
        "children": []
    }

    # Copy relevant content based on node type
    if node_type == "decision":
        new_node["question"] = original_node.get("question", "")
        if decision and decision.get("answer"):
            new_node["question"] += f"\n\nAnswer: {decision['answer']}"
    elif node_type == "action":
        new_node["title"] = original_node.get("title", original_node.get("action", ""))
        if decision and decision.get("action_performed"):
            new_node["title"] = decision["action_performed"]
        if decision and decision.get("command_output"):
            output = decision["command_output"].strip()
            if output:
                new_node["title"] += f"\n\nCommand Output:\n{output}"
    elif node_type == "solution":
        new_node["title"] = original_node.get("title", original_node.get("solution", ""))

    return new_node


def _create_node_from_custom_step(
    custom_step: dict[str, Any],
    step_id: str
) -> dict[str, Any]:
    """Create a node from a custom step.

    Args:
        custom_step: Custom step dict
        step_id: ID of the custom step

    Returns:
        Node dict for the linear tree
    """
    step_type = custom_step.get("type", "action")
    content = custom_step.get("content", "")

    new_node = {
        "id": str(uuid.uuid4()),
        "type": step_type,
        "children": []
    }

    # Map content to appropriate field based on type
    if step_type == "decision":
        new_node["question"] = content
    elif step_type == "action":
        new_node["title"] = content
    elif step_type == "solution":
        new_node["title"] = content

    # Add notes if present
    if custom_step.get("notes"):
        if step_type == "decision":
            new_node["question"] += f"\n\nNotes: {custom_step['notes']}"
        elif step_type == "action":
            new_node["title"] += f"\n\nNotes: {custom_step['notes']}"
        elif step_type == "solution":
            new_node["title"] += f"\n\nNotes: {custom_step['notes']}"

    return new_node


def generate_tree_name_from_session(
    original_tree_name: str,
    ticket_number: str | None = None,
    client_name: str | None = None
) -> str:
    """Generate a descriptive name for the saved tree.

    Args:
        original_tree_name: Name of the original tree
        ticket_number: Optional ticket number
        client_name: Optional client name

    Returns:
        Generated tree name
    """
    parts = [original_tree_name, "Session"]

    if ticket_number:
        parts.append(f"(Ticket {ticket_number})")
    if client_name:
        parts.append(f"- {client_name}")

    return " ".join(parts)
