from __future__ import annotations import asyncio from contextlib import asynccontextmanager import httpx from fastapi import FastAPI from app.api.routes import get_router from app.bot.telegram_bot import TelegramBotRunner from app.clients.lastfm import LastFmClient from app.clients.spotify import SpotifyClient from app.config import get_settings from app.db.session import create_engine, create_session_factory, init_db from app.runtime import AppRuntime from app.services.app_services import AppServices from app.services.playlist_job import PlaylistJobService from app.services.recommendation import RecommendationEngine from app.services.spotify_auth import SpotifyAuthService def create_app() -> FastAPI: settings = get_settings() @asynccontextmanager async def lifespan(app: FastAPI): engine = create_engine(settings) session_factory = create_session_factory(engine) await init_db(engine) http_client = httpx.AsyncClient(headers={"User-Agent": "spotify-vibe-bot/1.0"}) spotify = SpotifyClient(settings, http_client) lastfm = LastFmClient(settings.lastfm_api_key, http_client) auth_service = SpotifyAuthService(settings, spotify, session_factory) rec_engine = RecommendationEngine(settings, spotify, lastfm) job_service = PlaylistJobService(settings, session_factory, auth_service, rec_engine, asyncio.Lock()) services = AppServices(auth=auth_service, recommendation=rec_engine, jobs=job_service) runtime = AppRuntime( settings=settings, engine=engine, session_factory=session_factory, http_client=http_client, spotify=spotify, lastfm=lastfm, generate_lock=job_service.generate_lock, ) app.state.runtime = runtime app.state.services = services telegram_runner = TelegramBotRunner( token=settings.telegram_bot_token, session_factory=session_factory, services=services, app_base_url=settings.app_base_url, ) runtime.telegram_runner = telegram_runner job_service.set_notifier(telegram_runner.send_message) await telegram_runner.start_polling() try: yield finally: await telegram_runner.stop() await http_client.aclose() await engine.dispose() app = FastAPI(title="Spotify Vibe Bot", lifespan=lifespan) app.include_router(get_router()) return app