"""Desktop → Orchestra runtime sync (capability snapshot, context, journal, goal memory).

Pre-decision sync bundle (Phase 2):
  Before POST /api/orchestra/decision, the desktop may call ``sync_pre_decision_bundle``
  to push capability snapshot + runtime context + optional goal memory in one orchestrated
  pass. Existing separate POST helpers remain the canonical low-level API — the bundle
  only sequences them and does not change payloads or endpoints.
"""

from __future__ import annotations

import logging
from typing import Any

logger = logging.getLogger(__name__)


def _paired_api_client():
    from ...shared.avatar_llm_cloud import load_desktop_cloud_credentials
    from ...core.api_client import PassiveApiClient

    creds = load_desktop_cloud_credentials()
    if creds is None:
        return None, None
    base_url, token = creds
    return PassiveApiClient(base_url=base_url), token


def post_capability_snapshot(snapshot: dict[str, Any]) -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        from iuve_connect_agents.shared.device_context_model import sanitize_dcm_for_cloud_sync

        payload = dict(snapshot or {})
        dcm = payload.get("device_context")
        if isinstance(dcm, dict):
            payload = dict(payload)
            payload["device_context"] = sanitize_dcm_for_cloud_sync(dcm)
        payload.pop("installed_apps", None)
        return client.post_capability_snapshot(auth_token=token, snapshot=payload)
    except Exception as exc:
        logger.debug("capability_snapshot_sync_failed: %s", exc)
        return None


def fetch_capability_graph() -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        return client.get_capability_graph(auth_token=token)
    except Exception as exc:
        logger.debug("capability_graph_fetch_failed: %s", exc)
        return None


def sync_runtime_context_to_server(metadata: dict[str, Any]) -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        return client.post_runtime_context(auth_token=token, context=metadata)
    except Exception as exc:
        logger.debug("runtime_context_sync_failed: %s", exc)
        return None


def emit_action_journal_event(event: dict[str, Any]) -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        return client.post_action_journal(auth_token=token, event=event)
    except Exception as exc:
        logger.debug("action_journal_emit_failed: %s", exc)
        return None


def query_server_goal_memory(*, query: str, topic: str = "") -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        return client.query_goal_memory(auth_token=token, query=query, topic=topic)
    except Exception as exc:
        logger.debug("goal_memory_query_failed: %s", exc)
        return None


def upsert_server_goal_memory(entry: dict[str, Any]) -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        return client.upsert_goal_memory(auth_token=token, entry=entry)
    except Exception as exc:
        logger.debug("goal_memory_upsert_failed: %s", exc)
        return None


def emit_outcome_memory(outcome: dict[str, Any]) -> dict[str, Any] | None:
    client, token = _paired_api_client()
    if client is None or token is None:
        return None
    try:
        return client.post_outcome_memory(auth_token=token, outcome=outcome)
    except Exception as exc:
        logger.debug("outcome_memory_emit_failed: %s", exc)
        return None


def sync_pre_decision_bundle(
    *,
    capability_snapshot: dict[str, Any] | None = None,
    runtime_context: dict[str, Any] | None = None,
    goal_memory_entry: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """Orchestrate pre-decision sync without replacing separate POST helpers.

    Returns a summary dict with per-step results (None when skipped or unpaired).
    """
    results: dict[str, Any] = {
        "capability_snapshot": None,
        "runtime_context": None,
        "goal_memory": None,
    }
    if isinstance(capability_snapshot, dict) and capability_snapshot:
        results["capability_snapshot"] = post_capability_snapshot(capability_snapshot)
    if isinstance(runtime_context, dict) and runtime_context:
        results["runtime_context"] = sync_runtime_context_to_server(runtime_context)
    if isinstance(goal_memory_entry, dict) and goal_memory_entry:
        results["goal_memory"] = upsert_server_goal_memory(goal_memory_entry)
    return results
