"""Executor for RetryStrategyEditProposal.

Scope boundary: StrategyEngine does not read shot["pinned_strategy"] yet —
production loop wiring is a separate follow-on.
"""
from __future__ import annotations

import logging
from typing import Optional

from fastapi import HTTPException

from recoil.api.adapters import beats as beats_adapter
from recoil.api.eventbus import BUS

logger = logging.getLogger(__name__)

_SCOPE = "api/executors/retry_strategy_edit"

try:
    from recoil.pipeline.orchestrator.strategy_registry import RetryStrategyName
    _VALID_STRATEGY_NAMES: frozenset[str] = frozenset(
        s.value for s in RetryStrategyName
    )
except ImportError:
    _VALID_STRATEGY_NAMES: frozenset[str] = frozenset()


def execute(
    beat_id: str,
    strategy_name: str,
    rationale: str,
    project_id: Optional[str] = None,
) -> dict:
    """Raises HTTPException(422) if strategy_name is invalid; HTTPException(404) if beat not found."""
    if _VALID_STRATEGY_NAMES and strategy_name not in _VALID_STRATEGY_NAMES:
        raise HTTPException(
            status_code=422,
            detail={
                "error": "invalid_strategy_name",
                "strategy_name": strategy_name,
                "valid_names": sorted(_VALID_STRATEGY_NAMES),
                "message": f"Unknown retry strategy {strategy_name!r}",
            },
        )
    try:
        result = beats_adapter.pin_strategy(
            beat_id=beat_id,
            strategy_name=strategy_name,
            rationale=rationale,
            project_id=project_id,
        )
    except KeyError:
        BUS.emit_sync(
            severity="failure",
            scope=_SCOPE,
            summary=f"retry_strategy_edit_target_not_found: {beat_id}",
            payload={"beat_id": beat_id},
        )
        raise HTTPException(
            status_code=404,
            detail={
                "error": "beat_not_found",
                "beat_id": beat_id,
                "message": f"Cannot pin strategy: beat {beat_id!r} not found on disk.",
            },
        )
    BUS.emit_sync(
        severity="success",
        scope=_SCOPE,
        summary=f"retry_strategy_edit_applied: {beat_id} → {strategy_name}",
        payload={
            **result,
            "beat_id": beat_id,
            "rationale_length": len(rationale),
        },
    )
    return result
