import json
import logging
import logging.config
import time
import uuid

import yaml
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

from surya.endpoint.legacy import router as legacy_router
from surya.endpoint.openai import router as openai_router
from surya.endpoint.service import _error_response

with open("logger.yaml", "r", encoding="utf-8") as f:
    config = yaml.safe_load(f.read())
    logging.config.dictConfig(config)

logger = logging.getLogger(__name__)

app = FastAPI(
    title="OCR SERVICE API SERVICE",
    version="1.0",
    docs_url="/v1/api/ai/swagger",
    openapi_url="/v1/api/ai/openapi.json",
)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    request_id = getattr(request.state, "request_id", "-")
    logger.warning(
        "request_validation_failed request_id=%s method=%s path=%s errors=%s",
        request_id,
        request.method,
        request.url.path,
        exc.errors(),
    )
    return JSONResponse(
        status_code=200,
        content={
            "data": [],
            "message": json.dumps({"error info": exc.errors()}, default=str),
            "code": 422,
        },
    )


@app.middleware("http")
async def allow_openapi_unauthorized(request: Request, call_next):
    if request.url.path == "/v1/api/ai/openapi.json":
        response = await call_next(request)
        return response
    return await call_next(request)


@app.middleware("http")
async def log_request_response(request, call_next):
    request_id = uuid.uuid4().hex
    request.state.request_id = request_id
    start = time.perf_counter()
    client = request.client.host if request.client else "-"
    logger.info(
        "request_start request_id=%s method=%s path=%s client=%s",
        request_id,
        request.method,
        request.url.path,
        client,
    )
    try:
        response = await call_next(request)
    except Exception as e:
        duration_ms = (time.perf_counter() - start) * 1000
        logger.exception(
            "request_unhandled_exception request_id=%s method=%s path=%s duration_ms=%.2f",
            request_id,
            request.method,
            request.url.path,
            duration_ms,
            exc_info=True,
        )
        return JSONResponse(status_code=500, content=_error_response(e))
    duration_ms = (time.perf_counter() - start) * 1000
    logger.info(
        "request_end request_id=%s method=%s path=%s status_code=%s duration_ms=%.2f",
        request_id,
        request.method,
        request.url.path,
        response.status_code,
        duration_ms,
    )
    return response


app.include_router(legacy_router)
app.include_router(openai_router)
