"""Author: Vasiliy Zdanovskiy
email: vasilyvz@gmail.com

JSON-RPC handlers for transfer_ack and queue_job lifecycle WebSocket events.
"""

from __future__ import annotations

from typing import Any, Dict

from mcp_proxy_adapter.core.errors import ValidationError
from mcp_proxy_adapter.core.job_push.events import (
    EVENT_ARTIFACT_READY,
    EVENT_JOB_INPUT_ACCEPTED,
    EVENT_JOB_PROCESSING_STEP,
)
from mcp_proxy_adapter.core.job_push.queue_custom_push import (
    job_processing_step_should_emit,
    push_queue_job_ws_payload,
)


def _opt_str(params: Dict[str, Any], key: str) -> str:
    raw = params.get(key)
    if raw is None:
        return ""
    return str(raw).strip()


async def jsonrpc_transfer_ack(params: Dict[str, Any]) -> Dict[str, Any]:
    """Verify post-download checksum and mark download session consumed (idempotent)."""
    from mcp_proxy_adapter.api.handlers import get_transfer_store
    from mcp_proxy_adapter.core.job_push.events import EVENT_TRANSFER_RELEASED
    from mcp_proxy_adapter.core.job_push.transfer_push import (
        notify_transfer_state_changed,
    )

    tid = _opt_str(params, "transfer_id") or _opt_str(params, "outbound_transfer_id")
    if not tid:
        raise ValidationError(
            "transfer_id or outbound_transfer_id is required",
            data={"params": list(params.keys())},
        )
    algo = _opt_str(params, "checksum_algorithm") or "sha256"
    checksum = _opt_str(params, "checksum_value")
    if not checksum:
        raise ValidationError("checksum_value is required")
    job_raw = _opt_str(params, "job_id")
    job_kw: str | None = job_raw if job_raw else None
    store = get_transfer_store()
    result = dict(
        store.acknowledge_download_transfer(
            tid,
            checksum_algorithm=algo,
            checksum_value=checksum,
            job_id=job_kw,
        )
    )
    if result.get("success") and not result.get("idempotent"):
        await notify_transfer_state_changed(
            tid,
            EVENT_TRANSFER_RELEASED,
            {"direction": "download"},
        )
    return result


async def jsonrpc_job_input_accepted(params: Dict[str, Any]) -> Dict[str, Any]:
    """Emit job_input_accepted to queue_job WebSocket subscribers."""
    job_id = _opt_str(params, "job_id")
    if not job_id:
        raise ValidationError("job_id is required")
    inbound = _opt_str(params, "inbound_transfer_id")
    command = _opt_str(params, "command")
    if not command:
        raise ValidationError("command is required")
    filename = _opt_str(params, "filename")
    correlation_id = _opt_str(params, "correlation_id")
    body: Dict[str, Any] = {
        "event": EVENT_JOB_INPUT_ACCEPTED,
        "job_id": job_id,
        "command": command,
    }
    if inbound:
        body["inbound_transfer_id"] = inbound
    if filename:
        body["filename"] = filename
    if correlation_id:
        body["correlation_id"] = correlation_id
    await push_queue_job_ws_payload(body)
    return {"success": True, "event": EVENT_JOB_INPUT_ACCEPTED, "job_id": job_id}


async def jsonrpc_job_processing_step(params: Dict[str, Any]) -> Dict[str, Any]:
    """Emit job_processing_step (throttled per job_id)."""
    job_id = _opt_str(params, "job_id")
    if not job_id:
        raise ValidationError("job_id is required")
    step = _opt_str(params, "step")
    if not step:
        raise ValidationError("step is required")
    if not job_processing_step_should_emit(job_id):
        return {
            "success": True,
            "throttled": True,
            "job_id": job_id,
        }
    message = _opt_str(params, "message")
    progress_raw = params.get("progress_percent")
    progress = 0
    if isinstance(progress_raw, int):
        progress = max(0, min(100, progress_raw))
    elif isinstance(progress_raw, float):
        progress = max(0, min(100, int(progress_raw)))
    body: Dict[str, Any] = {
        "event": EVENT_JOB_PROCESSING_STEP,
        "job_id": job_id,
        "step": step,
        "message": message,
        "progress_percent": progress,
    }
    await push_queue_job_ws_payload(body)
    return {"success": True, "event": EVENT_JOB_PROCESSING_STEP, "job_id": job_id}


async def jsonrpc_artifact_ready(params: Dict[str, Any]) -> Dict[str, Any]:
    """Emit artifact_ready for a registered outbound transfer."""
    job_id = _opt_str(params, "job_id")
    if not job_id:
        raise ValidationError("job_id is required")
    outbound = _opt_str(params, "outbound_transfer_id")
    if not outbound:
        raise ValidationError("outbound_transfer_id is required")
    filename = _opt_str(params, "filename")
    if not filename:
        raise ValidationError("filename is required")
    algo = _opt_str(params, "checksum_algorithm") or "sha256"
    if algo != "sha256":
        raise ValidationError('checksum_algorithm must be "sha256"')
    checksum = _opt_str(params, "checksum_value")
    if not checksum:
        raise ValidationError("checksum_value is required")
    size_raw = params.get("size_bytes")
    if not isinstance(size_raw, int) or size_raw < 0:
        raise ValidationError("size_bytes must be a non-negative integer")
    correlation_id = _opt_str(params, "correlation_id")
    body: Dict[str, Any] = {
        "event": EVENT_ARTIFACT_READY,
        "job_id": job_id,
        "outbound_transfer_id": outbound,
        "filename": filename,
        "checksum_algorithm": algo,
        "checksum_value": checksum,
        "size_bytes": int(size_raw),
    }
    if correlation_id:
        body["correlation_id"] = correlation_id
    await push_queue_job_ws_payload(body)
    return {"success": True, "event": EVENT_ARTIFACT_READY, "job_id": job_id}
