import logging
from contextlib import asynccontextmanager
from datetime import datetime, timezone

from fastapi import FastAPI, HTTPException, Request, Depends
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse, Response
from prometheus_client import generate_latest, CONTENT_TYPE_LATEST
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text

# 必须在其他模块 import 之前初始化 JSON 日志
from app.logging_config import setup_logging
setup_logging()

from fastapi.middleware.cors import CORSMiddleware

from app.api.admin import router as admin_router
from app.api.content import router as content_router
from app.api.contents import router as contents_router
from app.api.clients import router as clients_router
from app.api.agents import router as agents_router
from app.api.knowledge import router as knowledge_router
from app.api.distribution import router as distribution_router
from app.api.analytics import router as analytics_router
from app.api.lifecycle import router as lifecycle_router
from app.api.auth import router as auth_router
from app.api.citations import router as citations_router
from app.api.queries import router as queries_router
from app.api.reports import router as reports_router
from app.api.subscriptions import router as subscription_router
from app.api.alerts import router as alerts_router
from app.api.dashboard import router as dashboard_router
from app.api.brands import router as brands_router
from app.api.diagnosis import router as diagnosis_router
from app.api.onboarding import router as onboarding_router
from app.api.platforms import router as platforms_router
from app.api.platform_rules import router as platform_rules_router
from app.api.image import router as image_router
from app.api.knowledge_graph import router as knowledge_graph_router
from app.api.ai_engines import router as ai_engines_router
from app.api.detection import router as detection_router
from app.api.api_keys import router as api_keys_router
from app.api.usage import router as usage_router
from app.config import settings
from app.database import engine, Base
from app.schemas.common import ErrorResponse, ErrorCode
from app.middleware.rate_limit import RateLimitMiddleware
from app.middleware.logging_middleware import RequestLoggingMiddleware
from app.middleware.request_id import RequestIdMiddleware
from app.middleware.metrics import MetricsMiddleware
from app.monitoring.middleware import MonitoringMiddleware
from app.database import get_db
from app.workers.scheduler import query_scheduler


@asynccontextmanager
async def lifespan(app: FastAPI):
    import app.models

    # 初始化监控模块
    import app.monitoring

    async with engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)

    query_scheduler.start()

    yield

    await query_scheduler.shutdown()


app = FastAPI(
    title="GEO Platform API",
    version="1.0.0",
    lifespan=lifespan,
)


@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
    """统一 HTTP 异常响应格式。"""
    code = ErrorCode.from_status(exc.status_code)
    return JSONResponse(
        status_code=exc.status_code,
        content=ErrorResponse(
            detail=str(exc.detail),
            code=code,
        ).model_dump(mode="json"),
    )


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError) -> JSONResponse:
    """统一参数校验异常响应格式。"""
    return JSONResponse(
        status_code=422,
        content=ErrorResponse(
            detail="请求参数校验失败",
            code=ErrorCode.VALIDATION_ERROR,
            extra={"errors": exc.errors()},
        ).model_dump(mode="json"),
    )


@app.exception_handler(Exception)
async def general_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    """兜底异常处理器，避免内部错误泄漏给客户端。"""
    logging.getLogger(__name__).exception("Unhandled exception: %s", exc)
    return JSONResponse(
        status_code=500,
        content=ErrorResponse(
            detail="服务器内部错误，请稍后重试",
            code=ErrorCode.INTERNAL_ERROR,
        ).model_dump(mode="json"),
    )

_allow_origins = [origin.strip() for origin in settings.CORS_ORIGINS.split(",") if origin.strip()]
if not _allow_origins:
    _allow_origins = ["http://localhost:3000"]

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

# 安全响应头
@app.middleware("http")
async def add_security_headers(request, call_next):
    response = await call_next(request)
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "DENY"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Referrer-Policy"] = "strict-origin-when-cross-origin"
    return response

# 中间件注册顺序（FastAPI 后进先出，最后注册的最先执行）
# 执行链：RequestId → Metrics → RateLimit → RequestLogging → CORS → SecurityHeaders
app.add_middleware(RequestLoggingMiddleware)
app.add_middleware(RateLimitMiddleware)
app.add_middleware(MetricsMiddleware)
app.add_middleware(MonitoringMiddleware)
app.add_middleware(RequestIdMiddleware)

app.include_router(auth_router, prefix="/api/v1/auth", tags=["认证"])
app.include_router(queries_router, prefix="/api/v1/queries", tags=["查询词"])
app.include_router(citations_router, prefix="/api/v1/citations", tags=["引用数据"])
app.include_router(reports_router, prefix="/api/v1/reports", tags=["报告"])
app.include_router(subscription_router)
app.include_router(admin_router)
app.include_router(agents_router, prefix="/api/v1/agents", tags=["Agent管理"])
app.include_router(lifecycle_router, prefix="/api/v1/lifecycle", tags=["lifecycle"])
app.include_router(knowledge_router, prefix="/api/v1/knowledge", tags=["知识库"])
app.include_router(content_router, prefix="/api/v1/content", tags=["内容生产"])
app.include_router(contents_router, prefix="/api/v1/contents", tags=["内容管理"])
app.include_router(clients_router, prefix="/api/v1/clients", tags=["客户管理"])
app.include_router(distribution_router, prefix="/api/v1/distribution", tags=["内容分发"])
app.include_router(analytics_router, prefix="/api/v1/analytics", tags=["监测优化"])
app.include_router(alerts_router, prefix="/api/v1/alerts", tags=["告警通知"])
app.include_router(dashboard_router, prefix="/api/v1/dashboard", tags=["仪表盘"])
app.include_router(brands_router, prefix="/api/v1/brands", tags=["品牌管理"])
app.include_router(diagnosis_router, prefix="/api/v1/diagnosis", tags=["诊断服务"])
app.include_router(onboarding_router, prefix="/api/v1")
app.include_router(platforms_router, prefix="/api/v1")
app.include_router(platform_rules_router)
app.include_router(image_router, prefix="/api/v1")
app.include_router(knowledge_graph_router, prefix="/api/v1")
app.include_router(ai_engines_router, prefix="/api/v1/ai-engines", tags=["AI引擎查询"])
app.include_router(detection_router, prefix="/api/v1/detection", tags=["定时检测任务"])
app.include_router(api_keys_router, prefix="/api/v1/api-keys", tags=["API Key管理"])
app.include_router(usage_router, prefix="/api/v1/usage", tags=["用量追踪"])


@app.get("/health", tags=["可观测性"])
async def health_check():
    """存活检查（Liveness）：服务进程是否运行正常。不依赖外部服务。"""
    return {
        "status": "healthy",
        "timestamp": datetime.now(timezone.utc).isoformat(),
    }


@app.get("/ready", tags=["可观测性"])
async def readiness_check(db: AsyncSession = Depends(get_db)):
    """就绪检查（Readiness）：依赖服务（DB / Redis）是否就绪。
    
    供 Kubernetes readinessProbe / Docker healthcheck 使用。
    不需要认证。
    """
    import redis.asyncio as aioredis  # type: ignore
    from app.config import settings as _settings

    # --- 检查数据库 ---
    try:
        await db.execute(text("SELECT 1"))
        db_ok = True
    except Exception:
        db_ok = False

    # --- 检查 Redis ---
    redis_ok = False
    try:
        redis_client = aioredis.from_url(_settings.REDIS_URL, socket_connect_timeout=2)
        await redis_client.ping()
        await redis_client.aclose()
        redis_ok = True
    except Exception:
        pass

    all_ok = db_ok and redis_ok
    return JSONResponse(
        status_code=200 if all_ok else 503,
        content={
            "status": "ready" if all_ok else "not_ready",
            "checks": {
                "database": "ok" if db_ok else "error",
                "redis": "ok" if redis_ok else "error",
            },
            "timestamp": datetime.now(timezone.utc).isoformat(),
        },
    )


@app.get("/metrics", tags=["可观测性"])
async def metrics():
    """Prometheus指标端点"""
    return Response(
        content=generate_latest(),
        media_type=CONTENT_TYPE_LATEST
    )


# ---- 详细健康检查端点 ----
from app.services.health_checker import HealthChecker
from app.services.app_state import app_state


@app.get("/health/detailed", tags=["可观测性"])
async def detailed_health(
    db: AsyncSession = Depends(get_db),
):
    """
    详细健康检查

    返回所有依赖组件的健康状态：
    - database: 数据库连接
    - redis: Redis缓存
    - llm_providers: LLM服务提供商
    - storage: 文件存储

    状态：
    - healthy: 所有组件正常
    - degraded: 部分组件异常，但仍可服务
    - unhealthy: 核心组件异常
    """
    checker = HealthChecker(db, settings.REDIS_URL)
    health_result = await checker.check_all()

    # 添加应用信息
    health_result["app"] = app_state.get_info()

    return health_result


@app.get("/health/liveness", tags=["可观测性"])
async def liveness():
    """
    存活探针

    用于Kubernetes livenessProbe
    只要应用进程存活就返回200
    """
    return {"status": "alive"}


@app.get("/health/readiness", tags=["可观测性"])
async def readiness(db: AsyncSession = Depends(get_db)):
    """
    就绪探针

    用于Kubernetes readinessProbe
    检查核心依赖是否就绪
    """
    checker = HealthChecker(db, settings.REDIS_URL)

    # 只检查核心依赖：数据库和Redis
    db_result = await checker.check_database()
    redis_result = await checker.check_redis()

    if db_result.healthy and redis_result.healthy:
        return {
            "status": "ready",
            "checks": {
                "database": db_result.healthy,
                "redis": redis_result.healthy,
            }
        }
    else:
        raise HTTPException(
            status_code=503,
            detail={
                "status": "not_ready",
                "checks": {
                    "database": db_result.healthy,
                    "redis": redis_result.healthy,
                }
            }
        )
