from typing import  Union

from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse, Response, StreamingResponse

from src.blackbox.blackbox_factory import BlackboxFactory
from src.log.loki_config import LokiLogger
import logging

from fastapi.middleware.cors import CORSMiddleware
from injector import Injector
import yaml

app = FastAPI()

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

injector = Injector()
blackbox_factory = injector.get(BlackboxFactory)

with open(".env.yaml", "r") as f:
    config = yaml.safe_load(f)
logger = LokiLogger(
    # url=config["loki"]["url"],
    # username=config["loki"]["username"],
    # password=config["loki"]["password"],
    tags=config["loki"]["labels"],
    logger_name=__name__,
    level=logging.DEBUG 
).get_logger()


@app.exception_handler(Exception)
async def catch_all_exceptions(request: Request, exc: Exception):
    """
    捕获所有在 ASGI 应用中未被处理的异常，并记录到 Loki。
    """
    logger.error(
        f"Unhandled exception in ASGI application for path: {request.url.path}, method: {request.method} - {exc}",
        exc_info=True, # 必须为 True，才能获取完整的堆栈信息
        extra={
            "path": request.url.path,
            "method": request.method,
            "error_type": type(exc).__name__,
            "error_message": str(exc)
        }
    )
    return JSONResponse(
        status_code=500,
        content={"message": "Internal Server Error", "detail": "An unexpected error occurred."}
    )

@app.post("/")
@app.get("/")
async def blackbox(blackbox_name: Union[str, None] = None, request: Request = None):
    if not blackbox_name:
        return JSONResponse(content={"error": "blackbox_name is required"}, status_code=status.HTTP_400_BAD_REQUEST)
    try:
        box = blackbox_factory.get_blackbox(blackbox_name)
    except ValueError as e:
        logger.error(f"获取 blackbox 失败: {blackbox_name} - {e}", exc_info=True)
        return JSONResponse(content={"error": "value error"}, status_code=status.HTTP_400_BAD_REQUEST)
    try:
        response = await box.fast_api_handler(request)
        # 检查响应的状态码，如果 >= 400，则认为是错误响应并记录
        if response.status_code >= 400:
            try:            
                decoded_content = response.body.decode('utf-8', errors='ignore') 
                logger.error(f"Blackbox 返回错误响应: URL={request.url}, Method={request.method}, Status={response.status_code}, Content={decoded_content}")
            except Exception as body_exc:
                logger.error(f"Blackbox {blackbox_name} 返回错误响应: URL={request.url}, Method={request.method}, Status={response.status_code}, 无法解析响应内容: {body_exc}")
        return response 
    except Exception as e:
        logger.error(f"Blackbox 内部抛出异常: URL={request.url}, Method={request.method}, 异常报错: {type(e).__name__}: {e}", exc_info=True)
        return JSONResponse(
            status_code=500,
            content={"message": "Internal Server Error", "detail": "An unexpected error occurred."}
        )

# @app.get("/audio/{filename}")
# async def serve_audio(filename: str):
#     import os
#     # 确保文件存在
#     if os.path.exists(filename):
#         with open(filename, 'rb') as f:
#             audio_data = f.read()
#             if filename.endswith(".mp3"):
#                 # 对于 MP3 文件，设置为 inline 以在浏览器中播放
#                 return Response(content=audio_data, media_type="audio/mpeg", headers={"Content-Disposition": f"inline; filename={filename}"})
#             elif filename.endswith(".wav"):
#                 # 对于 WAV 文件，设置为 inline 以在浏览器中播放
#                 return Response(content=audio_data, media_type="audio/wav", headers={"Content-Disposition": f"inline; filename={filename}"})
#     else:
#         return JSONResponse(content={"error": f"{filename} not found"}, status_code=status.HTTP_404_NOT_FOUND)

@app.get("/audio/audio_files/{filename}")
async def serve_audio(filename: str):
    import os
    import aiofiles
    filename = os.path.join("audio_files", filename)
    # 确保文件存在
    if os.path.exists(filename):
        try:
            # 使用 aiofiles 异步读取文件
            async with aiofiles.open(filename, 'rb') as f:
                audio_data = await f.read()

            # 根据文件类型返回正确的音频响应
            if filename.endswith(".mp3"):
                return Response(content=audio_data, media_type="audio/mpeg", headers={"Content-Disposition": f"inline; filename={filename}"})
            elif filename.endswith(".wav"):
                return Response(content=audio_data, media_type="audio/wav", headers={"Content-Disposition": f"inline; filename={filename}"})
            else:
                return JSONResponse(content={"error": "Unsupported audio format"}, status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE)
        except asyncio.CancelledError:
            # 处理任务被取消的情况
            return JSONResponse(content={"error": "Request was cancelled"}, status_code=status.HTTP_400_BAD_REQUEST)
        except Exception as e:
            # 捕获其他异常
            return JSONResponse(content={"error": str(e)}, status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
    else:
        return JSONResponse(content={"error": f"{filename} not found"}, status_code=status.HTTP_404_NOT_FOUND)


# @app.get("/audio/{filename}")
# async def serve_audio(filename: str):
#     import os
#     file_path = f"audio/{filename}"
#     # 检查文件是否存在
#     if os.path.exists(file_path):
#         return StreamingResponse(open(file_path, "rb"), media_type="audio/mpeg" if filename.endswith(".mp3") else "audio/wav")
#     else:
#         return JSONResponse(content={"error": f"{filename} not found"}, status_code=404)