"""
文件上传路由
"""
import logging
from typing import List
from fastapi import APIRouter, File, UploadFile, Form, HTTPException, BackgroundTasks, Depends
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session

from models import (
    FileCheckRequest, ChunkUploadRequest, FileMergeRequest, 
    FileUploadResponse, FileInfo, UploadRecordsResponse, UploadRecordItem
)
from services import file_upload_service, notify_upload_complete
from token_middleware import get_current_user, check_dataset_permission, check_file_size_permission
from token_auth import AuthenticatedUser
from config import settings
from database import get_db, FileUploadRecord
from db_token_manager import get_db_token_manager

# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

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


@router.post("/check", response_model=FileUploadResponse, summary="检查文件上传状态")
async def check_file_status(
    request: FileCheckRequest,
    current_user: AuthenticatedUser = Depends(get_current_user)
):
    """
    检查文件上传状态，支持断点续传
    
    - **file_id**: 文件唯一标识符
    - **file_name**: 原始文件名
    - **file_size**: 文件总大小(字节)
    - **total_chunks**: 分片总数
    - **file_md5**: 文件MD5值(可选)
    """
    try:
        # 检查数据集权限
        if not check_dataset_permission(current_user, request.dataset_id):
            return FileUploadResponse.error(
                code=403,
                message=f"无权访问数据集: {request.dataset_id}"
            )
        
        # 检查文件大小权限
        if not check_file_size_permission(current_user, request.file_size):
            return FileUploadResponse.error(
                code=413,
                message=f"文件大小超过用户限制，最大允许 {current_user.max_file_size / (1024**3):.1f}GB"
            )
        
        # 检查文件类型
        if settings.allowed_file_types:
            file_ext = request.file_name.split('.')[-1].lower()
            if file_ext not in settings.allowed_file_types:
                return FileUploadResponse.error(
                    code=400,
                    message=f"不支持的文件类型: {file_ext}"
                )
        
        file_info = await file_upload_service.check_file_status(
            file_id=request.file_id,
            file_name=request.file_name,
            file_size=request.file_size,
            total_chunks=request.total_chunks,
            dataset_id=request.dataset_id,
            file_md5=request.file_md5
        )
        
        return FileUploadResponse.success(
            message="文件状态检查成功",
            file_id=file_info.file_id,
            file_name=file_info.file_name,
            uploaded_chunks=file_info.uploaded_chunks,
            is_completed=file_info.is_completed,
            file_size=file_info.file_size,
            progress=file_info.progress
        )
        
    except Exception as e:
        logger.error(f"检查文件状态失败: {str(e)}")
        return FileUploadResponse.error(message=f"检查文件状态失败: {str(e)}")


@router.post("/chunk", response_model=FileUploadResponse, summary="上传文件分片")
async def upload_chunk(
    file_id: str = Form(..., description="文件唯一标识符"),
    file_name: str = Form(..., description="原始文件名"),
    file_size: int = Form(..., description="文件总大小"),
    chunk_index: int = Form(..., description="分片序号"),
    total_chunks: int = Form(..., description="分片总数"),
    chunk_size: int = Form(..., description="分片大小"),
    dataset_id: str = Form(..., description="数据集ID"),
    chunk_md5: str = Form(None, description="分片MD5值"),
    file_md5: str = Form(None, description="文件MD5值"),
    chunk_file: UploadFile = File(..., description="分片文件数据"),
    current_user: AuthenticatedUser = Depends(get_current_user)
):
    """
    上传文件分片
    
    - **file_id**: 文件唯一标识符
    - **chunk_index**: 当前分片序号(从0开始)
    - **chunk_file**: 分片文件数据
    - 其他参数用于验证和记录
    """
    try:
        # 验证请求参数
        request = ChunkUploadRequest(
            file_id=file_id,
            file_name=file_name,
            file_size=file_size,
            chunk_index=chunk_index,
            total_chunks=total_chunks,
            chunk_size=chunk_size,
            dataset_id=dataset_id,
            chunk_md5=chunk_md5,
            file_md5=file_md5
        )
        
        # 读取分片数据
        chunk_data = await chunk_file.read()
        
        # 验证分片大小
        if len(chunk_data) != chunk_size:
            return FileUploadResponse.error(
                code=400,
                message=f"分片大小不匹配，期望: {chunk_size}, 实际: {len(chunk_data)}"
            )
        
        # 上传分片
        success = await file_upload_service.upload_chunk(
            file_id=file_id,
            chunk_index=chunk_index,
            chunk_data=chunk_data,
            chunk_md5=chunk_md5
        )
        
        if not success:
            return FileUploadResponse.error(message="分片上传失败")
        
        # 获取更新后的文件信息
        file_info = file_upload_service.get_file_info(file_id)
        if not file_info:
            return FileUploadResponse.error(message="获取文件信息失败")
        
        return FileUploadResponse.success(
            message=f"分片 {chunk_index} 上传成功",
            file_id=file_info.file_id,
            file_name=file_info.file_name,
            uploaded_chunks=file_info.uploaded_chunks,
            is_completed=file_info.is_completed,
            file_size=file_info.file_size,
            progress=file_info.progress
        )
        
    except ValueError as e:
        return FileUploadResponse.error(code=400, message=str(e))
    except Exception as e:
        logger.error(f"上传分片失败: {str(e)}")
        return FileUploadResponse.error(message=f"上传分片失败: {str(e)}")


@router.post("/merge", response_model=FileUploadResponse, summary="合并文件分片")
async def merge_chunks(
    request: FileMergeRequest,
    background_tasks: BackgroundTasks,
    current_user: AuthenticatedUser = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    合并文件分片，完成文件上传

    - **file_id**: 文件唯一标识符
    - **file_name**: 目标文件名
    - **total_chunks**: 分片总数
    - **file_md5**: 文件MD5值(可选，用于校验)
    """
    try:
        # 检查数据集权限
        if not check_dataset_permission(current_user, request.dataset_id):
            return FileUploadResponse.error(
                code=403,
                message=f"无权访问数据集: {request.dataset_id}"
            )

        # 合并分片并保存记录
        success, file_path = await file_upload_service.merge_chunks(
            file_id=request.file_id,
            target_filename=request.file_name,
            file_md5=request.file_md5,
            db=db,
            user_id=current_user.user_id,
            user_name=current_user.user_name,
            token_hash=current_user.token_hash
        )

        if not success:
            return FileUploadResponse.error(message="文件合并失败")

        # 文件上传完成，记录每日上传计数
        token_mgr = get_db_token_manager()
        token_mgr.record_upload_complete(current_user.token_hash)

        # 上传成功，异步通知前端
        background_tasks.add_task(
            notify_upload_complete,
            dataset_id=request.dataset_id,
            file_path=file_path,
            user_id=current_user.user_id,
        )

        # 构建文件访问URL
        file_url = f"/api/download/{request.dataset_id}/{request.file_name}"

        return FileUploadResponse.success(
            message="文件上传完成",
            file_id=request.file_id,
            file_name=request.file_name,
            file_url=file_url,
            is_completed=True,
            progress=100.0
        )

    except ValueError as e:
        return FileUploadResponse.error(code=400, message=str(e))
    except Exception as e:
        logger.error(f"合并文件失败: {str(e)}")
        return FileUploadResponse.error(message=f"合并文件失败: {str(e)}")


@router.get("/status/{file_id}", response_model=FileUploadResponse, summary="获取文件上传状态")
async def get_upload_status(file_id: str):
    """
    获取文件上传状态
    
    - **file_id**: 文件唯一标识符
    """
    try:
        file_info = file_upload_service.get_file_info(file_id)
        if not file_info:
            return FileUploadResponse.error(code=404, message="文件信息不存在")
        
        return FileUploadResponse.success(
            message="获取状态成功",
            file_id=file_info.file_id,
            file_name=file_info.file_name,
            uploaded_chunks=file_info.uploaded_chunks,
            is_completed=file_info.is_completed,
            file_size=file_info.file_size,
            progress=file_info.progress
        )
        
    except Exception as e:
        logger.error(f"获取文件状态失败: {str(e)}")
        return FileUploadResponse.error(message=f"获取文件状态失败: {str(e)}")


@router.delete("/{file_id}", response_model=FileUploadResponse, summary="取消文件上传")
async def cancel_upload(file_id: str, background_tasks: BackgroundTasks):
    """
    取消文件上传，清理临时文件
    
    - **file_id**: 文件唯一标识符
    """
    try:
        file_info = file_upload_service.get_file_info(file_id)
        if not file_info:
            return FileUploadResponse.error(code=404, message="文件信息不存在")
        
        # 异步清理临时文件
        background_tasks.add_task(file_upload_service._cleanup_temp_files, file_id)
        
        # 移除文件信息
        file_upload_service.remove_file_info(file_id)
        
        return FileUploadResponse.success(message="上传已取消，临时文件已清理")
        
    except Exception as e:
        logger.error(f"取消上传失败: {str(e)}")
        return FileUploadResponse.error(message=f"取消上传失败: {str(e)}")


@router.get("/records", response_model=UploadRecordsResponse, summary="查询上传记录")
async def get_upload_records(
    page: int = 1,
    page_size: int = 10,
    user_id: str = None,
    dataset_id: str = None,
    file_name: str = None,
    current_user: AuthenticatedUser = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    查询上传记录（支持分页和筛选）
    
    - **page**: 页码（从1开始）
    - **page_size**: 每页大小（默认10，最大100）
    - **user_id**: 按用户ID筛选（可选，管理员可查询所有用户，普通用户只能查询自己的）
    - **dataset_id**: 按数据集ID筛选（可选）
    - **file_name**: 按文件名模糊搜索（可选）
    """
    try:
        # 参数验证
        if page < 1:
            page = 1
        if page_size < 1:
            page_size = 10
        if page_size > 100:
            page_size = 100
        
        # 权限检查：普通用户只能查询自己的记录
        query_user_id = user_id
        if current_user.role.value != "admin":
            query_user_id = current_user.user_id
        
        # 构建查询
        query = db.query(FileUploadRecord)
        
        # 筛选条件
        if query_user_id:
            query = query.filter(FileUploadRecord.user_id == query_user_id)
        
        if dataset_id:
            query = query.filter(FileUploadRecord.dataset_id == dataset_id)
        
        if file_name:
            query = query.filter(FileUploadRecord.file_name.like(f"%{file_name}%"))
        
        # 获取总数
        total = query.count()
        
        # 分页查询（按创建时间倒序）
        records = query.order_by(FileUploadRecord.created_at.desc())\
            .offset((page - 1) * page_size)\
            .limit(page_size)\
            .all()
        
        # 转换为响应模型
        record_items = []
        for record in records:
            record_dict = record.to_dict()
            record_items.append(UploadRecordItem(**record_dict))
        
        return UploadRecordsResponse.success(
            records=record_items,
            total=total,
            page=page,
            page_size=page_size,
            message=f"查询成功，共 {total} 条记录"
        )
        
    except Exception as e:
        logger.error(f"查询上传记录失败: {str(e)}")
        return UploadRecordsResponse.error(message=f"查询失败: {str(e)}")


@router.get("/records/stats", summary="获取上传统计信息")
async def get_upload_stats(
    current_user: AuthenticatedUser = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    获取用户的上传统计信息
    
    - 总上传文件数
    - 总上传文件大小
    - 今日上传文件数
    - 今日上传文件大小
    """
    try:
        from sqlalchemy import func
        from datetime import datetime, timedelta
        
        user_id = current_user.user_id
        
        # 总文件数和总大小
        total_result = db.query(
            func.count(FileUploadRecord.id).label('count'),
            func.sum(FileUploadRecord.file_size).label('size')
        ).filter(FileUploadRecord.user_id == user_id).first()
        
        total_count = total_result.count or 0
        total_size = total_result.size or 0
        
        # 今日上传
        today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
        today_result = db.query(
            func.count(FileUploadRecord.id).label('count'),
            func.sum(FileUploadRecord.file_size).label('size')
        ).filter(
            FileUploadRecord.user_id == user_id,
            FileUploadRecord.created_at >= today
        ).first()
        
        today_count = today_result.count or 0
        today_size = today_result.size or 0
        
        return {
            "code": 200,
            "message": "统计信息获取成功",
            "data": {
                "total_files": total_count,
                "total_size": total_size,
                "total_size_gb": round(total_size / (1024**3), 2),
                "today_files": today_count,
                "today_size": today_size,
                "today_size_gb": round(today_size / (1024**3), 2)
            }
        }
        
    except Exception as e:
        logger.error(f"获取统计信息失败: {str(e)}")
        return {
            "code": 500,
            "message": f"获取统计信息失败: {str(e)}"
        }


# 下载路由
download_router = APIRouter(prefix="/api/download", tags=["文件下载"])


@download_router.get("/{dataset_id}/{filename}", summary="下载文件")
async def download_file(dataset_id: str, filename: str):
    """
    下载已上传的文件

    - **dataset_id**: 数据集ID
    - **filename**: 文件名
    """
    import os
    file_path = os.path.join(settings.upload_base_dir, dataset_id, "full", "download", filename)
    
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail="文件不存在")
    
    return FileResponse(
        path=file_path,
        filename=filename,
        media_type='application/octet-stream'
    )
