"""Optional post-run reflection for web-act fresh_run (Phase 3B)."""

from __future__ import annotations

import json
import logging
import os
from typing import Any

_log = logging.getLogger(__name__)


def _reflection_enabled() -> bool:
    try:
        from core.config import get_web_act_config

        return bool(get_web_act_config().get("reflection_enabled", False))
    except Exception:
        return False


def _reflection_max_chars() -> int:
    try:
        from core.config import get_web_act_config

        return max(120, int(get_web_act_config().get("reflection_max_chars") or 600))
    except Exception:
        return 600


def _run_dir_in_scope(run_dir: str, *, task_metadata: dict[str, Any] | None) -> bool:
    run_dir_abs = os.path.abspath(os.path.expanduser(run_dir))
    try:
        from core.config import get_workspace_path

        ws = os.path.abspath(os.path.expanduser(get_workspace_path()))
    except Exception:
        ws = os.path.abspath(os.path.expanduser("~/.mugi/workspace"))
    web_runs_root = os.path.join(ws, "web_runs")
    if not run_dir_abs.startswith(web_runs_root + os.sep):
        return False
    tm = task_metadata if isinstance(task_metadata, dict) else {}
    task_id = str(tm.get("_task_id") or tm.get("task_id") or "").strip()
    if task_id:
        expected = f"/web_runs/kanban_{task_id}/"
        if expected not in run_dir_abs.replace("\\", "/") + "/":
            return False
    return True


def _skeleton_summary(validated: dict[str, Any]) -> str:
    answer = str(validated.get("answer") or "").strip()
    paths = validated.get("paths") or []
    n_paths = len(paths) if isinstance(paths, list) else 0
    if answer:
        return f"Web-act run ok: {answer[:200]} ({n_paths} artifact(s))."
    return f"Web-act run finished with {n_paths} artifact(s); no answer in result.json."


def reflect_web_act_run(
    run_dir: str,
    *,
    task_metadata: dict[str, Any] | None = None,
) -> dict[str, Any]:
    """Summarize a validated fresh_run directory (utility model optional)."""
    from tools.web_act import validate_web_act_result

    if not run_dir or not os.path.isdir(run_dir):
        return {"summary": "", "error": "run_dir missing"}
    if not _run_dir_in_scope(run_dir, task_metadata=task_metadata):
        return {"summary": "", "error": "run_dir outside web_act scope"}

    validated = validate_web_act_result(run_dir, fresh_run_expected=True)
    if not _reflection_enabled():
        return {"summary": _skeleton_summary(validated), "source": "skeleton"}

    cap = _reflection_max_chars()
    stdout_tail = ""
    stdout_path = os.path.join(run_dir, "stdout.log")
    if os.path.isfile(stdout_path):
        try:
            with open(stdout_path, "r", encoding="utf-8", errors="replace") as f:
                stdout_tail = f.read()[-2000:]
        except Exception:
            pass

    result_snippet = ""
    result_path = os.path.join(run_dir, "result.json")
    if os.path.isfile(result_path):
        try:
            with open(result_path, "r", encoding="utf-8") as f:
                result_snippet = json.dumps(json.load(f), ensure_ascii=False)[:800]
        except Exception:
            pass

    prompt = (
        "Summarize this web automation run for the operator in 2-4 sentences. "
        "Mention the answer, any failure, and one concrete next step if blocked.\n\n"
        f"result.json: {result_snippet}\n"
        f"stdout tail:\n{stdout_tail}\n"
    )
    try:
        from utility_model import is_available, utility_complete

        if is_available():
            text = utility_complete(
                [{"role": "user", "content": prompt}],
                max_tokens=min(400, cap // 2),
                temperature=0.3,
                activity_operation="web_act_reflection",
            )
            summary = str(text or "").strip()[:cap]
            if summary:
                return {"summary": summary, "source": "utility"}
    except Exception:
        _log.debug("web_act reflection utility call failed", exc_info=True)

    return {"summary": _skeleton_summary(validated)[:cap], "source": "skeleton"}


def append_reflection_to_active_run(task_id: str, reflection_summary: str) -> None:
    """Best-effort persist reflection on the active kanban run metadata."""
    if not (task_id and reflection_summary):
        return
    try:
        from utils.kanban_dispatcher import current_claim_token
        import kanban_storage as ks

        claim = current_claim_token()
        if not claim or claim[0] != task_id:
            return
        ks.patch_active_run_metadata(
            task_id,
            expected_token=claim[1],
            updates={"reflection_summary": reflection_summary[:2000]},
            fail_open=True,
        )
    except Exception:
        _log.debug("append_reflection_to_active_run failed", exc_info=True)
