import subprocess
import time
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from sqlalchemy.exc import ProgrammingError

from app.api.auth.router import auth_router  # Import the authentication router
from app.api.course.router import course_router
from app.api.company.router import company_router
from app.api.vessel.router import vessel_router
from app.api.seafarer.router import seafarer_router
from app.config import settings  # Import configuration settings
from app.database.main.mongo import (
    MongoDBSingleton,  # Import MongoDB singleton instance
)
from sqlalchemy.exc import OperationalError
from app.exceptions import (
    handle_generic_exception_handler,
    handle_programming_error,
    http_exception_error_handler,
    handel_operational_error_handler,
    handel_attribute_error_handler
)
from app.utils.schemas_utils import CustomResponse

mongodb_instance = MongoDBSingleton()  # Initialize MongoDB singleton instance

@asynccontextmanager
async def lifespan(_app: FastAPI):
    """Initialize the application."""
    # Load the MongoDB instance
    _ = mongodb_instance

    yield  # Yield control back to the application

app = FastAPI(
    title=settings.PROJECT_NAME,
    version=settings.API_VERSION,
    description=settings.DESCRIPTION,
    # docs_url=None,  # Optionally disable the interactive API docs
    # redoc_url=None,  # Optionally disable the ReDoc docs
    lifespan=lifespan,  # Set the lifespan context manager
    debug=True,  # Enable debug mode
)

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    try:
        response = await call_next(request)  # Normal processing
    except HTTPException as exc:
        # Convert HTTPException into proper JSON response
        return JSONResponse(status_code=exc.status_code, content={"detail": exc.detail})
    except Exception as exc:
        # Catch all other exceptions
        return JSONResponse(status_code=500, content={"detail": str(exc)})

    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

# Add CORS middleware to the application
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Allow all origins (set to a list of allowed origins for production)
    allow_credentials=True,
    allow_methods=["*"],  # Allow all HTTP methods
    allow_headers=["*"],  # Allow all HTTP headers
    expose_headers=["*"],  # Expose all headers
)

# Include the authentication router with prefix and tags
app.include_router(auth_router, prefix="/FASTAPI", tags=["AUTH"])
app.include_router(course_router, prefix="/FASTAPI", tags=["Course"])
app.include_router(company_router,prefix="/FASTAPI", tags=["Company"])
app.include_router(vessel_router,prefix="/FASTAPI", tags=["Vessel"])
app.include_router(seafarer_router,prefix="/FASTAPI", tags=["Seafarer"])


# HTTP Exception Handler
@app.exception_handler(HTTPException)
async def exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
    """Handle HTTP exceptions."""
    return http_exception_error_handler(request, exc)  # Use custom HTTP exception handler

# MySQL Exception Handler
@app.exception_handler(ProgrammingError)
async def programming_error_handler(request: Request, exc: ProgrammingError) -> JSONResponse:
    """Handle MySQL ProgrammingError exceptions."""
    return await handle_programming_error(request, exc)  # Use custom programming error handler

# General Exceptions
@app.exception_handler(Exception)
async def generic_exception_handler(request: Request, exc: Exception) -> JSONResponse:
    """Handle generic exceptions."""
    return await handle_generic_exception_handler(request, exc)  # Use custom generic exception handler

# Operational Errors
@app.exception_handler(OperationalError)
async def operational_error_handler(request: Request, exc: OperationalError) -> HTTPException:
    raise await handel_operational_error_handler(request, exc)

# Attribute Errors
@app.exception_handler(AttributeError)
async def attribute_error_handler(request: Request, exc: AttributeError)-> HTTPException:
    return await handel_attribute_error_handler(request, exc)

# Run Migrations
@app.get("/migrate",response_model_exclude_none=True)
async def run_migrations(message: str)-> CustomResponse:
    try:
        # subprocess.run(['alembic', 'downgrade', '<revision>'], shell=True)
        # Run Alembic revision command
        subprocess.run(['alembic', 'revision', '--autogenerate', '-m', '"{}"'.format(message)])
        # Run Alembic upgrade command
        subprocess.run(
            ["alembic", "upgrade", "head"]
        )
        return CustomResponse(status="1", message="Migration successful")
    
    except subprocess.CalledProcessError as e:
        raise HTTPException(status_code=500, detail=str(e))
    
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


