"""
文件上传 API 路由

处理 Skill 参考文件的上传、管理和删除
"""
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File
from typing import List, Optional
from pydantic import BaseModel
import shutil
from pathlib import Path

from app.core.skills.skill_manager import get_skill_manager, SkillManager
from app.utils.logger import get_logger

logger = get_logger(__name__)

router = APIRouter(prefix="/uploads", tags=["文件上传"])


class FileListResponse(BaseModel):
    """文件列表响应"""
    skill_id: str
    files: List[dict]


@router.post("/skills/{skill_id}/references")
async def upload_reference_file(
    skill_id: str,
    file: UploadFile = File(...),
    skill_manager: SkillManager = Depends(get_skill_manager)
):
    """
    上传 Skill 参考文件

    上传的文件将保存到 skill 的 references/ 目录
    支持的文件类型：.md, .txt, .json, .yaml, .yml
    """
    # 验证 Skill 存在且为 user 类型
    skill = await skill_manager.load_skill(skill_id)
    if not skill:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Skill 不存在: {skill_id}"
        )

    if skill.type == 'builtin':
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="不允许上传文件到 builtin Skill"
        )

    # 验证文件类型
    allowed_extensions = {'.md', '.txt', '.json', '.yaml', '.yml', '.pdf', '.doc', '.docx'}
    file_ext = Path(file.filename).suffix.lower()
    if file_ext not in allowed_extensions:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"不支持的文件类型: {file_ext}。支持的类型: {', '.join(allowed_extensions)}"
        )

    # 确保 references 目录存在
    skill_path = skill_manager._find_skill_path(skill_id)
    references_dir = skill_path.parent / "references"
    references_dir.mkdir(exist_ok=True)

    # 保存文件
    file_path = references_dir / file.filename
    try:
        with file_path.open("wb") as buffer:
            shutil.copyfileobj(file.file, buffer)

        logger.info(f"文件上传成功: {skill_id}/references/{file.filename}")

        return {
            "success": True,
            "message": "文件上传成功",
            "file": {
                "name": file.filename,
                "path": str(file_path.relative_to(skill_manager.skills_dir)),
                "size": file_path.stat().st_size
            }
        }

    except Exception as e:
        logger.error(f"文件上传失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"文件上传失败: {str(e)}"
        )


@router.get("/skills/{skill_id}/references", response_model=FileListResponse)
async def list_reference_files(
    skill_id: str,
    skill_manager: SkillManager = Depends(get_skill_manager)
):
    """
    列出 Skill 的所有参考文件
    """
    skill = await skill_manager.load_skill(skill_id)
    if not skill:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Skill 不存在: {skill_id}"
        )

    skill_path = skill_manager._find_skill_path(skill_id)
    references_dir = skill_path.parent / "references"

    files = []
    if references_dir.exists():
        for file_path in references_dir.iterdir():
            if file_path.is_file():
                files.append({
                    "name": file_path.name,
                    "size": file_path.stat().st_size,
                    "modified": file_path.stat().st_mtime
                })

    return FileListResponse(skill_id=skill_id, files=files)


@router.delete("/skills/{skill_id}/references/{filename}")
async def delete_reference_file(
    skill_id: str,
    filename: str,
    skill_manager: SkillManager = Depends(get_skill_manager)
):
    """
    删除 Skill 的参考文件
    """
    skill = await skill_manager.load_skill(skill_id)
    if not skill:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Skill 不存在: {skill_id}"
        )

    if skill.type == 'builtin':
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="不允许删除 builtin Skill 的文件"
        )

    skill_path = skill_manager._find_skill_path(skill_id)
    references_dir = skill_path.parent / "references"
    file_path = references_dir / filename

    if not file_path.exists():
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"文件不存在: {filename}"
        )

    try:
        file_path.unlink()
        logger.info(f"文件删除成功: {skill_id}/references/{filename}")

        return {"success": True, "message": "文件删除成功"}

    except Exception as e:
        logger.error(f"文件删除失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"文件删除失败: {str(e)}"
        )


@router.get("/skills/{skill_id}/references/{filename}")
async def get_reference_file(
    skill_id: str,
    filename: str,
    skill_manager: SkillManager = Depends(get_skill_manager)
):
    """
    读取 Skill 参考文件内容（用于预览）
    """
    skill = await skill_manager.load_skill(skill_id)
    if not skill:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"Skill 不存在: {skill_id}"
        )

    skill_path = skill_manager._find_skill_path(skill_id)
    references_dir = skill_path.parent / "references"
    file_path = references_dir / filename

    if not file_path.exists():
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=f"文件不存在: {filename}"
        )

    try:
        content = file_path.read_text(encoding='utf-8')
        return {
            "success": True,
            "filename": filename,
            "content": content
        }

    except UnicodeDecodeError:
        # 二进制文件（如 PDF）无法读取为文本
        return {
            "success": True,
            "filename": filename,
            "content": None,
            "binary": True,
            "message": "这是二进制文件，无法预览内容"
        }

    except Exception as e:
        logger.error(f"文件读取失败: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"文件读取失败: {str(e)}"
        )
