"""
统一的 Models API 端点

根据请求头认证方式自动返回对应格式:
- x-api-key + anthropic-version -> Claude 格式
- x-goog-api-key (header) 或 ?key= 参数 -> Gemini 格式
- Authorization: Bearer (bearer) -> OpenAI 格式
"""

from typing import Optional, Tuple, Union

from fastapi import APIRouter, Depends, Query, Request
from fastapi.responses import JSONResponse
from sqlalchemy.orm import Session

from src.api.base.models_service import (
    AccessRestrictions,
    ModelInfo,
    find_model_by_id,
    get_available_provider_ids,
    list_available_models,
)
from src.core.api_format_metadata import API_FORMAT_DEFINITIONS, ApiFormatDefinition
from src.core.enums import APIFormat
from src.core.logger import logger
from src.database import get_db
from src.models.database import ApiKey, User
from src.services.auth.service import AuthService

router = APIRouter(tags=["System Catalog"])

# 各格式对应的 API 格式列表
# 注意: CLI 格式是透传格式，Models API 只返回非 CLI 格式的端点支持的模型
_CLAUDE_FORMATS = [APIFormat.CLAUDE.value]
_OPENAI_FORMATS = [APIFormat.OPENAI.value]
_GEMINI_FORMATS = [APIFormat.GEMINI.value]


def _extract_api_key_from_request(
    request: Request, definition: ApiFormatDefinition
) -> Optional[str]:
    """根据格式定义从请求中提取 API Key"""
    auth_header = definition.auth_header.lower()
    auth_type = definition.auth_type

    header_value = request.headers.get(auth_header)
    if not header_value:
        # Gemini 还支持 ?key= 参数
        if definition.api_format in (APIFormat.GEMINI, APIFormat.GEMINI_CLI):
            return request.query_params.get("key")
        return None

    if auth_type == "bearer":
        # Bearer token: "Bearer xxx"
        if header_value.lower().startswith("bearer "):
            return header_value[7:].strip()
        return None
    else:
        # header 类型: 直接使用值
        return header_value


def _detect_api_format_and_key(request: Request) -> Tuple[str, Optional[str]]:
    """
    根据请求头检测 API 格式并提取 API Key

    检测顺序:
    1. x-api-key + anthropic-version -> Claude
    2. x-goog-api-key (header) 或 ?key= -> Gemini
    3. Authorization: Bearer -> OpenAI (默认)

    Returns:
        (api_format, api_key) 元组
    """
    # Claude: x-api-key + anthropic-version (必须同时存在)
    claude_def = API_FORMAT_DEFINITIONS[APIFormat.CLAUDE]
    claude_key = _extract_api_key_from_request(request, claude_def)
    if claude_key and request.headers.get("anthropic-version"):
        return "claude", claude_key

    # Gemini: x-goog-api-key (header 类型) 或 ?key=
    gemini_def = API_FORMAT_DEFINITIONS[APIFormat.GEMINI]
    gemini_key = _extract_api_key_from_request(request, gemini_def)
    if gemini_key:
        return "gemini", gemini_key

    # OpenAI: Authorization: Bearer (默认)
    # 注意: 如果只有 x-api-key 但没有 anthropic-version，也走 OpenAI 格式
    openai_def = API_FORMAT_DEFINITIONS[APIFormat.OPENAI]
    openai_key = _extract_api_key_from_request(request, openai_def)
    # 如果 OpenAI 格式没有 key，但有 x-api-key，也用它（兼容）
    if not openai_key and claude_key:
        openai_key = claude_key
    return "openai", openai_key


def _get_formats_for_api(api_format: str) -> list[str]:
    """获取对应 API 格式的端点格式列表"""
    if api_format == "claude":
        return _CLAUDE_FORMATS
    elif api_format == "gemini":
        return _GEMINI_FORMATS
    else:
        return _OPENAI_FORMATS


def _build_empty_list_response(api_format: str) -> dict:
    """根据 API 格式构建空列表响应"""
    if api_format == "claude":
        return {"data": [], "has_more": False, "first_id": None, "last_id": None}
    elif api_format == "gemini":
        return {"models": []}
    else:
        return {"object": "list", "data": []}


def _filter_formats_by_restrictions(
    formats: list[str], restrictions: AccessRestrictions, api_format: str
) -> Tuple[list[str], Optional[dict]]:
    """
    根据访问限制过滤 API 格式

    Returns:
        (过滤后的格式列表, 空响应或None)
        如果过滤后为空，返回对应格式的空响应
    """
    if restrictions.allowed_api_formats is None:
        return formats, None
    # 统一转为大写比较，兼容数据库中存储的大小写
    allowed_upper = {f.upper() for f in restrictions.allowed_api_formats}
    filtered = [f for f in formats if f.upper() in allowed_upper]
    if not filtered:
        logger.info(f"[Models] API Key 不允许访问格式 {api_format}")
        return [], _build_empty_list_response(api_format)
    return filtered, None


def _authenticate(db: Session, api_key: Optional[str]) -> Tuple[Optional[User], Optional[ApiKey]]:
    """
    认证 API Key

    Returns:
        (user, api_key_record) 元组，认证失败返回 (None, None)
    """
    if not api_key:
        logger.debug("[Models] 认证失败: 未提供 API Key")
        return None, None

    result = AuthService.authenticate_api_key(db, api_key)
    if not result:
        logger.debug("[Models] 认证失败: API Key 无效")
        return None, None

    user, key_record = result
    logger.debug(f"[Models] 认证成功: {user.email} (Key: {key_record.name})")
    return result


def _build_auth_error_response(api_format: str) -> JSONResponse:
    """根据 API 格式构建认证错误响应"""
    if api_format == "claude":
        return JSONResponse(
            status_code=401,
            content={
                "type": "error",
                "error": {
                    "type": "authentication_error",
                    "message": "Invalid API key provided",
                },
            },
        )
    elif api_format == "gemini":
        return JSONResponse(
            status_code=401,
            content={
                "error": {
                    "code": 401,
                    "message": "API key not valid. Please pass a valid API key.",
                    "status": "UNAUTHENTICATED",
                }
            },
        )
    else:
        return JSONResponse(
            status_code=401,
            content={
                "error": {
                    "message": "Incorrect API key provided. You can find your API key at https://platform.openai.com/account/api-keys.",
                    "type": "invalid_request_error",
                    "param": None,
                    "code": "invalid_api_key",
                }
            },
        )


# ============================================================================
# 响应构建函数
# ============================================================================


def _build_claude_list_response(
    models: list[ModelInfo],
    before_id: Optional[str],
    after_id: Optional[str],
    limit: int,
) -> dict:
    """构建 Claude 格式的列表响应"""
    model_data_list = [
        {
            "id": m.id,
            "type": "model",
            "display_name": m.display_name,
            "created_at": m.created_at,
        }
        for m in models
    ]

    # 处理分页
    start_idx = 0
    if after_id:
        for i, m in enumerate(model_data_list):
            if m["id"] == after_id:
                start_idx = i + 1
                break

    end_idx = len(model_data_list)
    if before_id:
        for i, m in enumerate(model_data_list):
            if m["id"] == before_id:
                end_idx = i
                break

    paginated = model_data_list[start_idx:end_idx][:limit]

    first_id = paginated[0]["id"] if paginated else None
    last_id = paginated[-1]["id"] if paginated else None
    has_more = len(model_data_list[start_idx:end_idx]) > limit

    return {
        "data": paginated,
        "has_more": has_more,
        "first_id": first_id,
        "last_id": last_id,
    }


def _build_openai_list_response(models: list[ModelInfo]) -> dict:
    """构建 OpenAI 格式的列表响应"""
    data = [
        {
            "id": m.id,
            "object": "model",
            "created": m.created_timestamp,
            "owned_by": m.provider_name,
        }
        for m in models
    ]
    return {"object": "list", "data": data}


def _build_gemini_list_response(
    models: list[ModelInfo],
    page_size: int,
    page_token: Optional[str],
) -> dict:
    """构建 Gemini 格式的列表响应"""
    # 处理分页
    start_idx = 0
    if page_token:
        try:
            start_idx = int(page_token)
        except ValueError:
            start_idx = 0

    end_idx = start_idx + page_size
    paginated_models = models[start_idx:end_idx]

    models_data = [
        {
            "name": f"models/{m.id}",
            "baseModelId": m.id,
            "version": "001",
            "displayName": m.display_name,
            "description": m.description or f"Model {m.id}",
            "inputTokenLimit": m.context_limit if m.context_limit is not None else 128000,
            "outputTokenLimit": m.output_limit if m.output_limit is not None else 8192,
            "supportedGenerationMethods": ["generateContent", "countTokens"],
            "temperature": 1.0,
            "maxTemperature": 2.0,
            "topP": 0.95,
            "topK": 64,
        }
        for m in paginated_models
    ]

    response: dict = {"models": models_data}
    if end_idx < len(models):
        response["nextPageToken"] = str(end_idx)

    return response


def _build_claude_model_response(model_info: ModelInfo) -> dict:
    """构建 Claude 格式的模型详情响应"""
    return {
        "id": model_info.id,
        "type": "model",
        "display_name": model_info.display_name,
        "created_at": model_info.created_at,
    }


def _build_openai_model_response(model_info: ModelInfo) -> dict:
    """构建 OpenAI 格式的模型详情响应"""
    return {
        "id": model_info.id,
        "object": "model",
        "created": model_info.created_timestamp,
        "owned_by": model_info.provider_name,
    }


def _build_gemini_model_response(model_info: ModelInfo) -> dict:
    """构建 Gemini 格式的模型详情响应"""
    return {
        "name": f"models/{model_info.id}",
        "baseModelId": model_info.id,
        "version": "001",
        "displayName": model_info.display_name,
        "description": model_info.description or f"Model {model_info.id}",
        "inputTokenLimit": model_info.context_limit if model_info.context_limit is not None else 128000,
        "outputTokenLimit": model_info.output_limit if model_info.output_limit is not None else 8192,
        "supportedGenerationMethods": ["generateContent", "countTokens"],
        "temperature": 1.0,
        "maxTemperature": 2.0,
        "topP": 0.95,
        "topK": 64,
    }


# ============================================================================
# 404 响应
# ============================================================================


def _build_404_response(model_id: str, api_format: str) -> JSONResponse:
    """根据 API 格式构建 404 响应"""
    if api_format == "claude":
        return JSONResponse(
            status_code=404,
            content={
                "type": "error",
                "error": {"type": "not_found_error", "message": f"Model '{model_id}' not found"},
            },
        )
    elif api_format == "gemini":
        return JSONResponse(
            status_code=404,
            content={
                "error": {
                    "code": 404,
                    "message": f"models/{model_id} is not found",
                    "status": "NOT_FOUND",
                }
            },
        )
    else:
        return JSONResponse(
            status_code=404,
            content={
                "error": {
                    "message": f"The model '{model_id}' does not exist",
                    "type": "invalid_request_error",
                    "param": "model",
                    "code": "model_not_found",
                }
            },
        )


# ============================================================================
# 路由端点
# ============================================================================


@router.get("/v1/models", response_model=None)
async def list_models(
    request: Request,
    # Claude 分页参数
    before_id: Optional[str] = Query(None, description="返回此 ID 之前的结果 (Claude)"),
    after_id: Optional[str] = Query(None, description="返回此 ID 之后的结果 (Claude)"),
    limit: int = Query(20, ge=1, le=1000, description="返回数量限制 (Claude)"),
    # Gemini 分页参数
    page_size: int = Query(50, alias="pageSize", ge=1, le=1000, description="每页数量 (Gemini)"),
    page_token: Optional[str] = Query(None, alias="pageToken", description="分页 token (Gemini)"),
    db: Session = Depends(get_db),
) -> Union[dict, JSONResponse]:
    """
    列出可用模型（统一端点）

    根据请求头中的认证方式自动检测 API 格式，并返回相应格式的模型列表。
    此接口兼容 Claude、OpenAI 和 Gemini 三种 API 格式。

    **格式检测规则**
    - x-api-key + anthropic-version → Claude 格式
    - x-goog-api-key 或 ?key= → Gemini 格式
    - Authorization: Bearer → OpenAI 格式（默认）

    **查询参数**

    Claude 格式：
    - before_id: 返回此 ID 之前的结果，用于向前分页
    - after_id: 返回此 ID 之后的结果，用于向后分页
    - limit: 返回数量限制，默认 20，范围 1-1000

    Gemini 格式：
    - pageSize: 每页数量，默认 50，范围 1-1000
    - pageToken: 分页 token，用于获取下一页

    **返回字段**

    Claude 格式：
    - data: 模型列表，每个模型包含：
      - id: 模型标识符
      - type: "model"
      - display_name: 显示名称
      - created_at: 创建时间（ISO 8601 格式）
    - has_more: 是否有更多结果
    - first_id: 当前页第一个模型 ID
    - last_id: 当前页最后一个模型 ID

    OpenAI 格式：
    - object: "list"
    - data: 模型列表，每个模型包含：
      - id: 模型标识符
      - object: "model"
      - created: Unix 时间戳
      - owned_by: 提供商名称

    Gemini 格式：
    - models: 模型列表，每个模型包含：
      - name: 模型资源名称（如 models/gemini-pro）
      - baseModelId: 基础模型 ID
      - version: 版本号
      - displayName: 显示名称
      - description: 描述信息
      - inputTokenLimit: 输入 token 上限
      - outputTokenLimit: 输出 token 上限
      - supportedGenerationMethods: 支持的生成方法
      - temperature: 默认温度参数
      - maxTemperature: 最大温度参数
      - topP: Top-P 参数
      - topK: Top-K 参数
    - nextPageToken: 下一页的 token（如果有更多结果）

    **错误响应**
    401: API Key 无效或未提供（格式根据检测到的 API 格式返回）
    """
    api_format, api_key = _detect_api_format_and_key(request)
    logger.info(f"[Models] GET /v1/models | format={api_format}")

    # 认证
    user, key_record = _authenticate(db, api_key)
    if not user:
        return _build_auth_error_response(api_format)

    # 构建访问限制
    restrictions = AccessRestrictions.from_api_key_and_user(key_record, user)

    # 检查 API 格式限制
    formats = _get_formats_for_api(api_format)
    formats, empty_response = _filter_formats_by_restrictions(formats, restrictions, api_format)
    if empty_response is not None:
        return empty_response

    available_provider_ids = get_available_provider_ids(db, formats)
    if not available_provider_ids:
        return _build_empty_list_response(api_format)

    models = await list_available_models(db, available_provider_ids, formats, restrictions)
    logger.debug(f"[Models] 返回 {len(models)} 个模型")

    if api_format == "claude":
        return _build_claude_list_response(models, before_id, after_id, limit)
    elif api_format == "gemini":
        return _build_gemini_list_response(models, page_size, page_token)
    else:
        return _build_openai_list_response(models)


@router.get("/v1/models/{model_id:path}", response_model=None)
async def retrieve_model(
    model_id: str,
    request: Request,
    db: Session = Depends(get_db),
) -> Union[dict, JSONResponse]:
    """
    获取单个模型详情（统一端点）

    根据请求头中的认证方式自动检测 API 格式，并返回相应格式的模型详情。
    此接口兼容 Claude、OpenAI 和 Gemini 三种 API 格式。

    **格式检测规则**
    - x-api-key + anthropic-version → Claude 格式
    - x-goog-api-key 或 ?key= → Gemini 格式
    - Authorization: Bearer → OpenAI 格式（默认）

    **路径参数**
    - model_id: 模型标识符（Gemini 格式支持 models/ 前缀，会自动移除）

    **返回字段**

    Claude 格式：
    - id: 模型标识符
    - type: "model"
    - display_name: 显示名称
    - created_at: 创建时间（ISO 8601 格式）

    OpenAI 格式：
    - id: 模型标识符
    - object: "model"
    - created: Unix 时间戳
    - owned_by: 提供商名称

    Gemini 格式：
    - name: 模型资源名称（如 models/gemini-pro）
    - baseModelId: 基础模型 ID
    - version: 版本号
    - displayName: 显示名称
    - description: 描述信息
    - inputTokenLimit: 输入 token 上限
    - outputTokenLimit: 输出 token 上限
    - supportedGenerationMethods: 支持的生成方法
    - temperature: 默认温度参数
    - maxTemperature: 最大温度参数
    - topP: Top-P 参数
    - topK: Top-K 参数

    **错误响应**
    401: API Key 无效或未提供
    404: 模型不存在或不可访问
    """
    api_format, api_key = _detect_api_format_and_key(request)

    # Gemini 格式的 name 带 "models/" 前缀，需要移除
    if api_format == "gemini" and model_id.startswith("models/"):
        model_id = model_id[7:]

    logger.info(f"[Models] GET /v1/models/{model_id} | format={api_format}")

    # 认证
    user, key_record = _authenticate(db, api_key)
    if not user:
        return _build_auth_error_response(api_format)

    # 构建访问限制
    restrictions = AccessRestrictions.from_api_key_and_user(key_record, user)

    # 检查 API 格式限制
    formats = _get_formats_for_api(api_format)
    formats, _ = _filter_formats_by_restrictions(formats, restrictions, api_format)
    if not formats:
        return _build_404_response(model_id, api_format)

    available_provider_ids = get_available_provider_ids(db, formats)
    model_info = find_model_by_id(db, model_id, available_provider_ids, formats, restrictions)

    if not model_info:
        return _build_404_response(model_id, api_format)

    if api_format == "claude":
        return _build_claude_model_response(model_info)
    elif api_format == "gemini":
        return _build_gemini_model_response(model_info)
    else:
        return _build_openai_model_response(model_info)


# Gemini 专用路径 /v1beta/models
@router.get("/v1beta/models", response_model=None)
async def list_models_gemini(
    request: Request,
    page_size: int = Query(50, alias="pageSize", ge=1, le=1000),
    page_token: Optional[str] = Query(None, alias="pageToken"),
    db: Session = Depends(get_db),
) -> Union[dict, JSONResponse]:
    """
    列出可用模型（Gemini v1beta 专用端点）

    Gemini API 的专用模型列表端点，使用 x-goog-api-key 或 ?key= 参数进行认证。
    返回 Gemini 格式的模型列表。

    **查询参数**
    - pageSize: 每页数量，默认 50，范围 1-1000
    - pageToken: 分页 token，用于获取下一页

    **返回字段**
    - models: 模型列表，每个模型包含：
      - name: 模型资源名称（如 models/gemini-pro）
      - baseModelId: 基础模型 ID
      - version: 版本号
      - displayName: 显示名称
      - description: 描述信息
      - inputTokenLimit: 输入 token 上限
      - outputTokenLimit: 输出 token 上限
      - supportedGenerationMethods: 支持的生成方法列表
      - temperature: 默认温度参数
      - maxTemperature: 最大温度参数
      - topP: Top-P 参数
      - topK: Top-K 参数
    - nextPageToken: 下一页的 token（如果有更多结果）

    **错误响应**
    401: API Key 无效或未提供
    """
    logger.info("[Models] GET /v1beta/models | format=gemini")

    # 从 x-goog-api-key 或 ?key= 提取 API Key
    gemini_def = API_FORMAT_DEFINITIONS[APIFormat.GEMINI]
    api_key = _extract_api_key_from_request(request, gemini_def)

    # 认证
    user, key_record = _authenticate(db, api_key)
    if not user:
        return _build_auth_error_response("gemini")

    # 构建访问限制
    restrictions = AccessRestrictions.from_api_key_and_user(key_record, user)

    # 检查 API 格式限制
    formats, empty_response = _filter_formats_by_restrictions(
        _GEMINI_FORMATS, restrictions, "gemini"
    )
    if empty_response is not None:
        return empty_response

    available_provider_ids = get_available_provider_ids(db, formats)
    if not available_provider_ids:
        return {"models": []}

    models = await list_available_models(db, available_provider_ids, formats, restrictions)
    logger.debug(f"[Models] 返回 {len(models)} 个模型")
    response = _build_gemini_list_response(models, page_size, page_token)
    logger.debug(f"[Models] Gemini 响应: {response}")
    return response


@router.get("/v1beta/models/{model_name:path}", response_model=None)
async def get_model_gemini(
    request: Request,
    model_name: str,
    db: Session = Depends(get_db),
) -> Union[dict, JSONResponse]:
    """
    获取单个模型详情（Gemini v1beta 专用端点）

    Gemini API 的专用模型详情端点，使用 x-goog-api-key 或 ?key= 参数进行认证。
    返回 Gemini 格式的模型详情。

    **路径参数**
    - model_name: 模型名称或资源路径（支持 models/ 前缀，会自动移除）

    **返回字段**
    - name: 模型资源名称（如 models/gemini-pro）
    - baseModelId: 基础模型 ID
    - version: 版本号
    - displayName: 显示名称
    - description: 描述信息
    - inputTokenLimit: 输入 token 上限
    - outputTokenLimit: 输出 token 上限
    - supportedGenerationMethods: 支持的生成方法列表
    - temperature: 默认温度参数
    - maxTemperature: 最大温度参数
    - topP: Top-P 参数
    - topK: Top-K 参数

    **错误响应**
    401: API Key 无效或未提供
    404: 模型不存在或不可访问
    """
    # 移除 "models/" 前缀（如果有）
    model_id = model_name[7:] if model_name.startswith("models/") else model_name
    logger.info(f"[Models] GET /v1beta/models/{model_id} | format=gemini")

    # 从 x-goog-api-key 或 ?key= 提取 API Key
    gemini_def = API_FORMAT_DEFINITIONS[APIFormat.GEMINI]
    api_key = _extract_api_key_from_request(request, gemini_def)

    # 认证
    user, key_record = _authenticate(db, api_key)
    if not user:
        return _build_auth_error_response("gemini")

    # 构建访问限制
    restrictions = AccessRestrictions.from_api_key_and_user(key_record, user)

    # 检查 API 格式限制
    formats, _ = _filter_formats_by_restrictions(_GEMINI_FORMATS, restrictions, "gemini")
    if not formats:
        return _build_404_response(model_id, "gemini")

    available_provider_ids = get_available_provider_ids(db, formats)
    model_info = find_model_by_id(
        db, model_id, available_provider_ids, formats, restrictions
    )

    if not model_info:
        return _build_404_response(model_id, "gemini")

    return _build_gemini_model_response(model_info)
