# -*- coding: utf-8 -*-
"""task-2686 regression — helper argv `--session` propagation.

회장 verbatim 7 항목 중 #1 (helper --session argv 자동 추가) 검증:
  - chair_facing_session_id 명시 → argv 에 ``--session <SID>`` 자동 첨부.
  - ANU_CHAIR_FACING_SID env var 단독 설정 → 동일 결과.
  - 명시값 우선 > env 폴백.
  - invalid UUID → argv 에 추가하지 않음 (silent skip).
  - 누락 → SESSION_PROPAGATION_GAP 후보 (argv 에 --session 미포함).
  - SELF-KEY callback → argv=None (chair_facing_sid 무관, fail-closed 우선).
"""
from __future__ import annotations

import importlib.util
import sys
from pathlib import Path

import pytest

_ROOT = Path(__file__).resolve().parents[3]
if str(_ROOT) not in sys.path:
    sys.path.insert(0, str(_ROOT))


def _load_real(modname: str, relpath: str):
    existing = sys.modules.get(modname)
    if existing is not None and getattr(existing, "__file__", "").endswith(relpath):
        return existing
    spec = importlib.util.spec_from_file_location(modname, _ROOT / relpath)
    assert spec is not None and spec.loader is not None
    mod = importlib.util.module_from_spec(spec)
    sys.modules[modname] = mod
    spec.loader.exec_module(mod)
    return mod


_load_real("dispatch.callback_owner_enforcer", "dispatch/callback_owner_enforcer.py")
_load_real("dispatch.normal_fallback_callback_helper", "dispatch/normal_fallback_callback_helper.py")

from dispatch.normal_fallback_callback_helper import (  # noqa: E402
    ANU_CHAIR_FACING_SID_ENV,
    CALLBACK_KIND_NORMAL,
    build_anu_owned_callback_request,
    is_valid_session_id,
    resolve_chair_facing_sid,
)


ANU_KEY = "c119085addb0f8b7"
EXECUTOR_KEY = "9c4f7c5e9c4f7c5e"  # 봇 self key sample (non-ANU)
VALID_SID = "53e89540-5bed-4692-a726-ed857820758a"
ANOTHER_VALID_SID = "12345678-1234-1234-1234-123456789abc"
INVALID_SID = "not-a-uuid"
ENVELOPE = (
    "task_id=task-2686\n"
    "result_path=memory/events/task-2686.result.json\n"
    "report_path=memory/reports/task-2686.md\n"
    "collector_role=ANU\n"
    "callback_kind=normal\n"
    f"owner_key={ANU_KEY}\n"
    "canonical_root=/home/jay/workspace\n"
)
AT = "2026-05-26 13:00:00"


@pytest.fixture(autouse=True)
def _clear_env(monkeypatch):
    monkeypatch.delenv(ANU_CHAIR_FACING_SID_ENV, raising=False)
    yield


def _request(*, chair_facing_session_id=None, owner_key=ANU_KEY):
    return build_anu_owned_callback_request(
        kind=CALLBACK_KIND_NORMAL,
        task_id="task-2686",
        executor_key=EXECUTOR_KEY,
        owner_key=owner_key,
        chat_id="6937032012",
        prompt=ENVELOPE,
        at=AT,
        cron_id="task-2686::normal",
        dispatch_cron_id="task-2686::dispatch",
        normal_collector_cron_id="task-2686::normal",
        no_fallback=True,
        chair_facing_session_id=chair_facing_session_id,
    )


def test_is_valid_session_id_uuid_form():
    assert is_valid_session_id(VALID_SID)
    assert is_valid_session_id(ANOTHER_VALID_SID)
    assert not is_valid_session_id(INVALID_SID)
    assert not is_valid_session_id("")
    assert not is_valid_session_id(None)
    assert not is_valid_session_id(VALID_SID[:-1])  # too short


def test_resolve_chair_facing_sid_explicit_priority(monkeypatch):
    monkeypatch.setenv(ANU_CHAIR_FACING_SID_ENV, ANOTHER_VALID_SID)
    # 명시값 우선
    assert resolve_chair_facing_sid(VALID_SID) == VALID_SID
    # 명시값 None → env fallback
    assert resolve_chair_facing_sid(None) == ANOTHER_VALID_SID


def test_resolve_chair_facing_sid_invalid_rejected(monkeypatch):
    monkeypatch.setenv(ANU_CHAIR_FACING_SID_ENV, INVALID_SID)
    assert resolve_chair_facing_sid(None) is None
    assert resolve_chair_facing_sid(INVALID_SID) is None


def test_helper_argv_includes_session_when_explicit_sid():
    req = _request(chair_facing_session_id=VALID_SID)
    assert req.ok, req.reasons
    assert req.argv is not None
    assert "--session" in req.argv
    sid_idx = req.argv.index("--session")
    assert req.argv[sid_idx + 1] == VALID_SID
    # --key 와 --session 양쪽 모두 존재
    assert "--key" in req.argv
    assert req.argv[req.argv.index("--key") + 1] == ANU_KEY


def test_helper_argv_includes_session_from_env(monkeypatch):
    monkeypatch.setenv(ANU_CHAIR_FACING_SID_ENV, VALID_SID)
    req = _request(chair_facing_session_id=None)
    assert req.ok, req.reasons
    assert "--session" in req.argv
    assert req.argv[req.argv.index("--session") + 1] == VALID_SID


def test_helper_argv_omits_session_when_sid_invalid():
    req = _request(chair_facing_session_id=INVALID_SID)
    assert req.ok, req.reasons
    # invalid sid → silent skip, --session 미첨부 (SESSION_PROPAGATION_GAP 후보)
    assert "--session" not in (req.argv or [])
    joined = "\n".join(req.reasons)
    assert "SESSION_PROPAGATION_GAP" in joined or "invalid" in joined.lower()


def test_helper_argv_omits_session_when_sid_missing():
    req = _request(chair_facing_session_id=None)
    assert req.ok, req.reasons
    assert "--session" not in (req.argv or [])


def test_helper_self_key_returns_none_argv_irrespective_of_sid():
    """self-key callback 은 SID 무관하게 argv=None (fail-closed 우선)."""
    req = _request(chair_facing_session_id=VALID_SID, owner_key=EXECUTOR_KEY)
    assert not req.ok
    assert req.argv is None
