from __future__ import annotations

import asyncio
from contextlib import asynccontextmanager

from fastapi import FastAPI

from ai_orchestrator.api.routes_openai_compat import (
    openai_compat_error_response,
    router as openai_compat_router,
)
from ai_orchestrator.api.routes_tasks import router as tasks_router
from ai_orchestrator.config.settings import Settings
from ai_orchestrator.services.openai_compat_service import OpenAICompatHTTPError, OpenAICompatService
from ai_orchestrator.services.task_service import TaskService, build_task_service, build_task_worker


def create_app(
    settings: Settings | None = None,
    task_service: TaskService | None = None,
    task_worker=None,
    openai_compat_service: OpenAICompatService | None = None,
) -> FastAPI:
    settings = settings or Settings()
    service = task_service or build_task_service(settings)
    worker = task_worker or (build_task_worker(settings) if settings.run_embedded_worker else None)
    chat_service = openai_compat_service or OpenAICompatService(settings=settings, task_service=service)

    @asynccontextmanager
    async def lifespan(app: FastAPI):
        app.state.settings = settings
        app.state.task_service = service
        app.state.task_worker = worker
        app.state.openai_compat_service = chat_service
        await service.recover_stale_tasks()
        worker_handle = None
        if worker is not None:
            worker_handle = asyncio.create_task(worker.run_forever())
        yield
        if worker_handle is not None:
            worker_handle.cancel()
            try:
                await worker_handle
            except asyncio.CancelledError:
                pass
        await service.shutdown()

    app = FastAPI(title=settings.app_name, lifespan=lifespan)
    app.include_router(tasks_router)
    app.include_router(openai_compat_router)
    app.add_exception_handler(OpenAICompatHTTPError, lambda request, exc: openai_compat_error_response(exc))

    @app.get("/health")
    async def health() -> dict[str, str]:
        return {"status": "ok"}

    return app
