from __future__ import annotations

import asyncio
import logging
import time
from contextlib import asynccontextmanager
from typing import AsyncGenerator

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from api import routes, ws as ws_router
from config.settings import settings
from execution.queue_handler import signal_queue
from price.updater import price_updater

logging.basicConfig(
    level=settings.LOG_LEVEL,
    format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
    datefmt="%Y-%m-%dT%H:%M:%S",
)
logger = logging.getLogger(__name__)


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    # ── بدء التشغيل ──────────────────────────────────────────────────────────
    logger.info(f"بوت التنفيذ يبدأ | الوضع={settings.TRADING_MODE} | المنفذ={settings.PORT}")

    # التقاط حلقة الأحداث قبل بدء الخيوط
    loop = asyncio.get_event_loop()
    price_updater.loop = loop

    # تحديث وقت البدء في routes
    import api.routes as _routes
    _routes._startup_time = time.time()

    # 1. بدء محدِّث الأسعار أولاً (لملء الذاكرة قبل بدء المستهلك)
    price_updater.start()

    # 2. بدء مستهلك قائمة الإشارات
    await signal_queue.start()

    logger.info(f"البوت جاهز على {settings.HOST}:{settings.PORT}")
    yield

    # ── الإيقاف ──────────────────────────────────────────────────────────────
    logger.info("إيقاف البوت...")
    await signal_queue.stop()
    price_updater.stop()
    logger.info("البوت أوقف بنجاح")


app = FastAPI(
    title="Execution Bot",
    description="بوت تنفيذ الصفقات وبث الأسعار لنظام التداول",
    version="1.0.0",
    lifespan=lifespan,
)

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

app.include_router(routes.router)
app.include_router(ws_router.router)


if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host=settings.HOST,
        port=settings.PORT,
        reload=False,
        log_level=settings.LOG_LEVEL.lower(),
    )
