import io
import os
import subprocess
import time
from collections.abc import Callable
from contextlib import asynccontextmanager

from fastapi import FastAPI, HTTPException, Query, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
from sqlalchemy.exc import ProgrammingError

from app.api.auth.router import auth_router
from app.api.admin.router import admin_router
from app.api.company_list.router import company_list_router
from app.api.vessel_list.router import vessel_router
from app.api.seafarer.router import seafarer_router
from app.api.tiket.router import tiket_router
from app.api.course_list.router import course_list_router
from app.api.company_mapping.router import company_mapping_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: Callable) -> Response:
    """
    Add process time header to the response.

    Args:
        request (Request): The incoming request.
        call_next (Callable): The next callable in the middleware chain.

    Returns:
        Response: The response with added process time header.
    """
    start_time = time.time()
    response = await call_next(request)  # Process the request
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)  # Add process time header to the response
    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(admin_router, prefix="/FASTAPI", tags=["ADMIN"])
app.include_router(company_list_router,prefix="/FASTAPI", tags=["COMPANY LIST"])
app.include_router(vessel_router,prefix="/FASTAPI", tags=["VESSEL LIST"])
app.include_router(seafarer_router,prefix="/FASTAPI", tags=["SEAFARERS LIST"])
app.include_router(tiket_router,prefix="/FASTAPI", tags=["TIKET"])
app.include_router(course_list_router,prefix="/FASTAPI", tags=["COURSE LIST"])
app.include_router(company_mapping_router,prefix="/FASTAPI", tags=["COMPANY MAPPING"])

# 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))


