"""Executor for ParameterChangeProposal.

Writes params_delta fields into the target take's dict within the shot JSON.
"""
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/param_tweak"


def execute(take_id: str, params_delta: dict, project_id: Optional[str] = None) -> dict:
    """Merge params_delta into the target take's dict on disk.

    Args:
        take_id: The take to update (e.g. "EP001_SH02_T001").
        params_delta: Key-value pairs to merge into the take dict.
        project_id: Optional project slug.

    Returns:
        {"shot_id": str, "take_id": str, "params_updated": list[str]}

    Raises:
        HTTPException(404): If take_id resolves to no take on disk.
    """
    try:
        result = beats_adapter.update_take_params(take_id, params_delta, project_id)
    except KeyError:
        BUS.emit_sync(
            severity="failure",
            scope=_SCOPE,
            summary=f"param_tweak_target_not_found: {take_id}",
            payload={"take_id": take_id},
        )
        raise HTTPException(
            status_code=404,
            detail={
                "error": "take_not_found",
                "take_id": take_id,
                "message": f"Cannot update params: take {take_id!r} not found on disk.",
            },
        )
    BUS.emit_sync(
        severity="success",
        scope=_SCOPE,
        summary=f"param_tweak_applied: {take_id}",
        payload={**result, "take_id": take_id, "params_delta_keys": list(params_delta.keys())},
    )
    return result
