from __future__ import annotations

import asyncio
import logging

from app.core.api.domain.models.agent_request import AgentRequest
from app.core.api.infrastructure.ids.request_id_factory import RequestIdFactory
from app.core.api.infrastructure.stores.in_memory_request_store import InMemoryRequestStore
from app.core.api.application.session_service import SessionService
from app.core.agent.runtime import AgentRuntime

LOGGER = logging.getLogger(__name__)


class RequestService:
    def __init__(
        self,
        request_store: InMemoryRequestStore,
        request_ids: RequestIdFactory,
        sessions: SessionService,
        runtime: AgentRuntime,
    ) -> None:
        self._request_store = request_store
        self._request_ids = request_ids
        self._sessions = sessions
        self._runtime = runtime

    async def create(self, session_id: str, message: str, process_version: str) -> AgentRequest:
        session = self._sessions.get(session_id)
        request = AgentRequest.create(
            request_id=self._request_ids.create(),
            session_id=session_id,
            message=message,
            process_version=process_version,
        )
        self._request_store.save(request)
        LOGGER.warning(
            "plugin request accepted: request_id=%s session_id=%s process_version=%s message=%s",
            request.request_id,
            session_id,
            process_version,
            (message or "").replace("\n", "\\n")[:500],
        )
        task = asyncio.create_task(self._runtime.run(request, session), name=f"agent-runtime:{request.request_id}")
        task.add_done_callback(self._log_task_result)
        return request

    def get(self, request_id: str) -> AgentRequest | None:
        return self._request_store.get(request_id)

    def _log_task_result(self, task: asyncio.Task) -> None:
        try:
            exc = task.exception()
        except asyncio.CancelledError:
            LOGGER.warning("agent runtime task cancelled: task=%s", task.get_name())
            return
        except Exception:
            LOGGER.exception("failed to inspect agent runtime task result: task=%s", task.get_name())
            return
        if exc is not None:
            LOGGER.exception("agent runtime task crashed: task=%s", task.get_name(), exc_info=exc)
