"""Reconcile linked drives when observation-approved kanban tasks terminate.

When a user approves a proactive observation that spawned a Kanban worker
(``tags`` includes ``observation-approved`` and ``metadata.drive_id`` is set),
terminal lifecycle events should update the originating drive so
``drive_action_cycle`` does not keep resurfacing the same work.

Failures here are retried briefly; persistent misses emit an activity warning.
"""

from __future__ import annotations

import logging
import time

_log = logging.getLogger(__name__)

_OBSERVATION_APPROVED_TAG = "observation-approved"
_TERMINAL_EVENTS = frozenset({"completed", "gave_up", "cancelled"})
_RECONCILE_RETRY_DELAYS_S = (0.0, 0.05, 0.15)


def _is_observation_approved_task(task: dict) -> bool:
    tags = task.get("tags") or []
    if not isinstance(tags, list):
        return False
    return _OBSERVATION_APPROVED_TAG in tags


def _task_drive_id(task: dict) -> str:
    meta = task.get("metadata") if isinstance(task.get("metadata"), dict) else {}
    return str(meta.get("drive_id") or "").strip()


def _latest_run_summary(task_id: str) -> str:
    import kanban_storage as ks

    runs = ks.list_runs(task_id, limit=1)
    if runs:
        return str(runs[0].get("summary") or "").strip()
    return ""


def _resolve_workspace() -> str | None:
    try:
        from core import get_workspace_path

        ws = str(get_workspace_path() or "").strip()
        return ws or None
    except Exception:
        return None


def _emit_drive_reconcile_missed(
    *,
    event_type: str,
    task_id: str,
    drive_id: str,
    message: str,
) -> None:
    try:
        from activity_bus import emit_activity_event

        emit_activity_event(
            {
                "source": "kanban",
                "kind": "observation_drive_reconcile_missed",
                "title": "Drive reconcile missed",
                "summary": (
                    f"Observation-linked drive {drive_id} not updated after "
                    f"kanban {event_type} on {task_id}: {message[:180]}"
                ),
                "tags": ["kanban", "proactive", "drive"],
                "meta": {
                    "task_id": task_id,
                    "drive_id": drive_id,
                    "event": event_type,
                    "error": message[:240],
                },
            }
        )
    except Exception:
        _log.debug("activity emit for drive reconcile miss failed", exc_info=True)


def maybe_reconcile_observation_drive_on_lifecycle(
    *,
    event_type: str,
    task_id: str,
    run_id: str = "",
) -> None:
    """Resolve or defer a linked drive when an observation-approved task ends."""
    if event_type not in _TERMINAL_EVENTS:
        return
    try:
        import kanban_storage as ks
        from utils.proactive_observation_drive import reconcile_linked_drive_on_observation_event

        task = ks.get_task(task_id)
        if not task or not _is_observation_approved_task(task):
            return
        drive_id = _task_drive_id(task)
        if not drive_id:
            return

        summary = _latest_run_summary(task_id) or str(task.get("title") or "")[:220]
        workspace = _resolve_workspace()
        last_msg = ""
        ok = False
        for delay in _RECONCILE_RETRY_DELAYS_S:
            if delay:
                time.sleep(delay)
            try:
                ok, last_msg = reconcile_linked_drive_on_observation_event(
                    drive_id,
                    event=event_type,
                    summary=summary,
                    task_id=task_id,
                    run_id=run_id or "",
                    workspace=workspace,
                )
            except Exception as exc:
                ok = False
                last_msg = str(exc)
            if ok:
                break

        if ok:
            _log.info(
                "Observation drive reconciled after kanban %s (drive=%s task=%s)",
                event_type,
                drive_id,
                task_id,
            )
        else:
            _log.warning(
                "Observation drive reconcile missed after kanban %s (drive=%s task=%s): %s",
                event_type,
                drive_id,
                task_id,
                last_msg,
            )
            _emit_drive_reconcile_missed(
                event_type=event_type,
                task_id=task_id,
                drive_id=drive_id,
                message=last_msg or "unknown",
            )
    except Exception:
        _log.warning(
            "Observation drive reconcile failed for task %s event=%s",
            task_id,
            event_type,
            exc_info=True,
        )
