import os
import uuid
import shutil
from fastapi import APIRouter, Depends, Request, UploadFile, File
from ...core.database import get_db
from ...core.permission import require_login
from ...core.config import settings

router = APIRouter()

# 允许的文件扩展名（与 capabilities API 保持一致）
ALLOWED_EXTENSIONS = {
    ".doc", ".docx", ".md", ".txt", ".xls", ".xlsx", ".csv",
    ".pdf",
    ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".tiff", ".tif"
}

MAX_FILE_SIZE = 20 * 1024 * 1024  # 20MB


def _get_upload_dir() -> str:
    """获取上传文件存储目录"""
    upload_dir = getattr(settings, "UPLOAD_DIR", "./uploads")
    chat_dir = os.path.join(upload_dir, "chat")
    os.makedirs(chat_dir, exist_ok=True)
    return chat_dir


def _is_allowed_file(filename: str, supports_vision: bool) -> bool:
    """检查文件类型是否允许"""
    ext = os.path.splitext(filename)[1].lower()
    if ext not in ALLOWED_EXTENSIONS:
        return False

    # 如果模型不支持视觉，禁止图片和 PDF
    if not supports_vision:
        image_exts = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".tiff", ".tif"}
        if ext in image_exts or ext == ".pdf":
            return False

    return True


@router.post("")
async def upload_chat_file(
    request: Request,
    file: UploadFile = File(...),
    thread_id: str = "",
    user: dict = Depends(require_login),
    db=Depends(get_db),
):
    """上传对话中的文件

    根据当前对话场景配置的模型能力（是否支持视觉），
    动态决定是否允许上传图片和 PDF 文件。
    """
    conn, cur = db

    # 1. 查询当前 user_chat 场景配置的模型是否支持视觉
    supports_vision = False
    await cur.execute(
        "SELECT config_value FROM system_configs WHERE config_key = 'model_selection_source'"
    )
    row = await cur.fetchone()
    source = row["config_value"] if row else "config_yaml"

    if source == "bff_api":
        await cur.execute(
            """SELECT m.supports_vision
               FROM ai_scene_model_configs sc
               JOIN ai_models m ON sc.model_id = m.id
               WHERE sc.scene_key = 'user_chat' AND m.enabled = 1
               ORDER BY sc.priority ASC
               LIMIT 1"""
        )
        model_row = await cur.fetchone()
        if model_row:
            supports_vision = bool(model_row["supports_vision"])
        else:
            # 回退到 default 场景
            await cur.execute(
                """SELECT m.supports_vision
                   FROM ai_scene_model_configs sc
                   JOIN ai_models m ON sc.model_id = m.id
                   WHERE sc.scene_key = 'default' AND m.enabled = 1
                   ORDER BY sc.priority ASC
                   LIMIT 1"""
            )
            model_row = await cur.fetchone()
            if model_row:
                supports_vision = bool(model_row["supports_vision"])
    else:
        # 从 config.yaml 读取
        try:
            import yaml
            deerflow_config_path = os.environ.get(
                "DEERFLOW_CONFIG_PATH",
                os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__)))),
                             "deer-flow", "config.yaml")
            )
            if os.path.exists(deerflow_config_path):
                with open(deerflow_config_path, "r", encoding="utf-8") as f:
                    config = yaml.safe_load(f) or {}
                models = config.get("models", [])
                if models:
                    supports_vision = bool(models[0].get("supports_vision", False))
        except Exception:
            pass

    # 2. 校验文件名和类型
    if not file.filename:
        return {"error": "文件名不能为空"}

    if not _is_allowed_file(file.filename, supports_vision):
        if not supports_vision:
            return {
                "error": "不支持的文件类型",
                "detail": f"当前模型不支持图片和PDF识别，仅支持: Word、Markdown、TXT、Excel"
            }
        return {"error": "不支持的文件类型"}

    # 3. 校验文件大小
    content = await file.read()
    if len(content) > MAX_FILE_SIZE:
        return {
            "error": "文件过大",
            "detail": f"最大允许 {MAX_FILE_SIZE // 1024 // 1024}MB"
        }

    # 4. 保存文件
    upload_dir = _get_upload_dir()
    file_ext = os.path.splitext(file.filename)[1].lower()
    unique_name = f"{uuid.uuid4().hex}{file_ext}"

    # 按用户ID和日期组织目录
    user_id = str(user.get("userId", "anonymous"))
    from datetime import datetime
    date_dir = datetime.now().strftime("%Y/%m/%d")
    target_dir = os.path.join(upload_dir, user_id, date_dir)
    os.makedirs(target_dir, exist_ok=True)

    file_path = os.path.join(target_dir, unique_name)
    with open(file_path, "wb") as f:
        f.write(content)

    # 5. 记录到数据库
    await cur.execute(
        """INSERT INTO chat_attachments
           (id, thread_id, user_id, original_name, stored_name, file_path,
            file_size, file_type, mime_type, created_at)
           VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())""",
        (
            str(uuid.uuid4()),
            thread_id or None,
            user_id,
            file.filename,
            unique_name,
            file_path,
            len(content),
            file_ext.lstrip("."),
            file.content_type or "application/octet-stream",
        ),
    )
    await conn.commit()

    # 6. 返回可访问的 URL
    # 使用相对路径，前端通过 /api/user/chat/upload/{filename} 访问
    file_url = f"/api/user/chat/upload/file/{user_id}/{date_dir}/{unique_name}"

    return {
        "success": True,
        "url": file_url,
        "original_name": file.filename,
        "size": len(content),
        "type": file_ext.lstrip("."),
    }


@router.get("/file/{user_id}/{year}/{month}/{day}/{filename}")
async def get_chat_file(
    user_id: str,
    year: str,
    month: str,
    day: str,
    filename: str,
    request: Request,
    user: dict = Depends(require_login),
):
    """获取上传的文件内容"""
    from fastapi.responses import FileResponse

    # 安全检查：只能访问自己的文件（管理员除外）
    current_user_id = str(user.get("userId", ""))
    if current_user_id != user_id and user.get("role") != "admin":
        return {"error": "无权访问该文件"}

    upload_dir = _get_upload_dir()
    file_path = os.path.join(upload_dir, user_id, year, month, day, filename)

    # 防止目录遍历攻击
    real_path = os.path.realpath(file_path)
    real_base = os.path.realpath(upload_dir)
    if not real_path.startswith(real_base):
        return {"error": "非法路径"}

    if not os.path.exists(file_path):
        return {"error": "文件不存在"}

    # 根据文件类型设置 content_type
    ext = os.path.splitext(filename)[1].lower()
    content_type_map = {
        ".jpg": "image/jpeg",
        ".jpeg": "image/jpeg",
        ".png": "image/png",
        ".gif": "image/gif",
        ".bmp": "image/bmp",
        ".webp": "image/webp",
        ".pdf": "application/pdf",
        ".doc": "application/msword",
        ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
        ".xls": "application/vnd.ms-excel",
        ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        ".csv": "text/csv",
        ".txt": "text/plain",
        ".md": "text/markdown",
    }
    content_type = content_type_map.get(ext, "application/octet-stream")

    return FileResponse(file_path, media_type=content_type, filename=filename)
