"""Detect action-session presets from Avatar execution plans (0.2.0.3)."""

from __future__ import annotations

from typing import Any

from ..active.action_session_store import ACTION_SESSION_PRESET_KEYS

COMMAND_TYPE_PRESET_MAP: dict[str, str] = {
    "browser_open_url": "web",
    "open_url": "web",
    "web_fetch_bounded": "web",
    "summarize_content": "web",
    "generate_content": "web",
    "insert_exact_text": "web",
    "open_web_composer": "web",
    "verify_workspace_file": "files",
    "public_accusation_post": "web",
    "social_post_publish": "web",
    "browser_click_publish": "web",
    "read_file_in_workspace": "files",
    "write_file_in_workspace": "files",
    "open_document_edit": "files",
    "open_folder": "files",
    "application_launch": "apps",
    "social_post_draft": "apps",
    "email_compose": "apps",
    "empty_trash": "files",
    "mouse_move_relative": "desktop",
    "keyboard_type_text": "desktop",
    "network_diagnostics": "network",
    "package_install_dry_run": "maintenance",
}

_PRESET_MERGE_ORDER: tuple[str, ...] = (
    "coding",
    "web",
    "files",
    "apps",
    "desktop",
    "network",
    "maintenance",
)


def _step_command_types(plan: dict[str, Any]) -> list[str]:
    steps = plan.get("steps") or []
    result: list[str] = []
    for step in steps:
        if not isinstance(step, dict):
            continue
        command_type = str(step.get("command_type") or "").strip().lower()
        if command_type:
            result.append(command_type)
    return result


def detect_plan_session_presets(plan: dict[str, Any]) -> set[str]:
    """Return preset keys implied by plan steps."""
    command_types = _step_command_types(plan)
    if not command_types:
        return set()

    has_web = any(COMMAND_TYPE_PRESET_MAP.get(ct) == "web" for ct in command_types)
    detected: set[str] = set()
    for command_type in command_types:
        if command_type == "keyboard_type_text":
            detected.add("web" if has_web else "desktop")
            continue
        preset = COMMAND_TYPE_PRESET_MAP.get(command_type)
        if preset:
            detected.add(preset)
    return detected


def detect_plan_session_preset(plan: dict[str, Any]) -> str | None:
    """Pick a single action-session preset for the plan, or None if not needed."""
    detected = detect_plan_session_presets(plan)
    if not detected:
        return None
    if detected in ({"files", "apps"}, {"files", "apps", "desktop"}):
        return "coding"
    if detected >= {"apps", "desktop"}:
        return "coding"
    # Mixed file + browser/desktop steps need coding (files preset alone lacks MANAGE_DESKTOP_APPS).
    if "files" in detected and detected & {"web", "apps", "desktop"}:
        return "coding"
    if len(detected) == 1:
        only = next(iter(detected))
        if only in ACTION_SESSION_PRESET_KEYS:
            return only
    for preset_key in _PRESET_MERGE_ORDER:
        if preset_key in detected:
            return preset_key
    return None


def active_session_covers_preset(active_sessions: list[dict[str, Any]], preset_key: str) -> bool:
    """True when an active session already matches or broadly covers the preset."""
    target = str(preset_key or "").strip().lower()
    if not target:
        return True
    coding_covers = {"files", "apps", "desktop"}
    for raw in active_sessions:
        if not isinstance(raw, dict):
            continue
        scope = raw.get("scope")
        if not isinstance(scope, dict):
            continue
        session_preset = str(scope.get("preset_key") or "").strip().lower()
        if not session_preset:
            continue
        if session_preset == target:
            return True
        if session_preset == "coding" and target in coding_covers:
            return True
        if session_preset == "web" and target == "desktop" and scope.get("keyboard_input"):
            return True
    return False


def plan_session_ttl_seconds(preset_key: str) -> int:
    from ..active.action_session_store import ActionSessionStore

    return int(ActionSessionStore.get_preset(preset_key).get("ttl_seconds") or 3600)
