"""
Contextra AI Analytics — Scenario Execution Layer (격리 실행기)

역할:
  - 등록된 시나리오들을 서로 독립적으로 격리 실행
  - 한 시나리오의 예외가 다른 시나리오에 영향을 주지 않음
  - 각 시나리오의 실패를 errors 목록에 기록
"""

from __future__ import annotations

import logging
from typing import Any, Dict, List


logger = logging.getLogger(__name__)


def execute_scenarios(
    detections: list[dict],
    private_key: str,
    stream_id: str,
    site_id: str,
    timestamp_utc_ms: int,
    active_scenarios: list[str] | None = None,
) -> tuple[list[dict], list[dict]]:
    """
    활성 시나리오들을 격리 실행하여 이벤트 목록 생성.

    Args:
        detections: 탐지 결과 목록 (raw dict format)
        private_key: 프레임 고유 식별자
        stream_id: 스트림 ID
        site_id: 사이트 ID
        timestamp_utc_ms: 타임스탬프
        active_scenarios: 실행할 시나리오 이름 목록 (None = 전체)

    Returns:
        (events, errors) — 이벤트 목록과 에러 목록
    """
    from . import scenario_registry as registry
    from .base_scenario import Detection

    strategy_map = registry.get_strategy_map()
    if not strategy_map:
        return [], []

    # 활성 시나리오 필터링
    if active_scenarios is None:
        resolved = list(strategy_map.keys())
    else:
        unknown = [s for s in active_scenarios if s not in strategy_map]
        if unknown:
            logger.error("[execution] Unknown scenarios requested: %s", unknown)
            raise ValueError(f"Unknown scenarios: {unknown}")
        resolved = list(active_scenarios)

    # 각 시나리오 격리 실행
    all_events: List[Dict[str, Any]] = []
    errors: List[Dict[str, str]] = []

    for scenario_name in resolved:
        scenario_instance = strategy_map[scenario_name]

        try:
            det_objects = [_raw_to_detection(d) for d in detections]
            events = scenario_instance.evaluate(
                detections=det_objects,
                private_key=private_key,
                stream_id=stream_id,
                site_id=site_id,
                timestamp_utc_ms=timestamp_utc_ms,
            )
            for event in events:
                all_events.append(event.to_dict())

        except Exception as exc:
            error_entry = {
                "scenario": scenario_name,
                "error_type": type(exc).__name__,
                "message": str(exc),
            }
            errors.append(error_entry)
            logger.error(
                "[execution] Scenario %s failed: %s: %s",
                scenario_name, type(exc).__name__, exc,
            )

    return all_events, errors


def _raw_to_detection(raw: dict) -> Detection:
    from .base_scenario import Detection as D
    return D(
        track_id=raw.get("track_id"),
        class_name=raw.get("class_name", "unknown"),
        confidence=float(raw.get("confidence", 0.0)),
        bbox=tuple(float(v) for v in raw.get("bbox", (0, 0, 0, 0))),
    )
