import logging
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.sessions import SessionMiddleware
import sentry_sdk
from sentry_sdk.integrations.fastapi import FastApiIntegration
import os
import sys
from app.api.api_router import api_router
from app.config import settings
from app.core.api_config import API_METADATA, API_TAGS
from app.auth import fastapi_users, auth_backend
from app.schemas.user import UserPublic, UserCreate, UserUpdate
from app.core.scheduler import init_scheduler, shutdown_scheduler
from app.core.middleware import RequestContextMiddleware
from app.core.logging_utils import PiiRedactionFilter
from app.core.error_handlers import sqlalchemy_exception_handler, generic_exception_handler
from app.core.rate_limiter import RateLimitMiddleware

if settings.SENTRY_DSN:
    sentry_sdk.init(
        dsn=settings.SENTRY_DSN,
        integrations=[
            FastApiIntegration(),
        ],
        traces_sample_rate=0.1 if settings.is_production else 1.0,
        environment=settings.ENVIRONMENT,
        send_default_pii=not settings.is_production
    )

logging.basicConfig(
    level=getattr(logging, settings.LOG_LEVEL),
    format=settings.LOG_FORMAT
)

# Attach PII redaction filter to root logger
root_logger = logging.getLogger()
root_logger.addFilter(PiiRedactionFilter())

logger = logging.getLogger(__name__)

api_metadata = {
    **API_METADATA,
    "docs_url": settings.docs_url,
    "redoc_url": settings.redoc_url,
    "openapi_url": settings.openapi_url,
}

app = FastAPI(
    **api_metadata,
    openapi_tags=API_TAGS
)

app.add_middleware(
    SessionMiddleware,
    secret_key=settings.SESSION_SECRET_KEY
)

# Structured logging & request tracing
app.add_middleware(RequestContextMiddleware)
app.add_middleware(RateLimitMiddleware)

app.add_middleware(
    CORSMiddleware,
    allow_origins=(settings.cors_origins_list if not settings.is_production else [settings.FRONTEND_URL]),
    # Credentials (cookies) are not required because we use JWTs in Authorization headers.
    allow_credentials=False,
    allow_methods=["*"],
    allow_headers=["*"],
    expose_headers=["*"]
)

# Register exception handlers BEFORE adding middleware/router
app.add_exception_handler(Exception, generic_exception_handler)
from sqlalchemy.exc import SQLAlchemyError
app.add_exception_handler(SQLAlchemyError, sqlalchemy_exception_handler)

app.include_router(api_router, prefix=settings.API_PREFIX)

@app.get("/health", tags=["Health"])
async def health_check():
    """Minimal health check endpoint that avoids leaking build metadata."""
    return {"status": settings.HEALTH_STATUS_OK}

@app.get("/", tags=["Root"])
async def read_root():
    """Public root endpoint with minimal information."""
    logger.info("Root endpoint '/' accessed.")
    return {"message": settings.ROOT_MESSAGE}

async def run_migrations():
    """Run database migrations."""
    try:
        logger.info("Running database migrations...")
        base_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        alembic_path = os.path.join(base_path, 'alembic')
        
        if alembic_path not in sys.path:
            sys.path.insert(0, alembic_path)
        
        from migrations import run_migrations as run_db_migrations
        await run_db_migrations()
        
        logger.info("Database migrations completed successfully.")
    except Exception as e:
        logger.error(f"Error running migrations: {e}")
        raise

@app.on_event("startup")
async def startup_event():
    """Initialize services on startup."""
    logger.info(f"Application startup in {settings.ENVIRONMENT} environment...")
    # await run_migrations()
    init_scheduler()
    logger.info("Application startup complete.")

@app.on_event("shutdown")
async def shutdown_event():
    """Cleanup services on shutdown."""
    logger.info("Application shutdown: Disconnecting from database...")
    shutdown_scheduler()
    # Close Redis connection pool to avoid leaking file descriptors.
    try:
        from app.core.redis import redis_pool
        await redis_pool.aclose()
        logger.info("Redis pool closed.")
    except Exception as e:
        logger.warning(f"Error closing Redis pool: {e}")
    logger.info("Application shutdown complete.")