"""
OSS 上传服务
流程：SDK 通过 oss2 直接上传到 OSS（OSS 即最终存储）
"""
import logging
from datetime import datetime
from typing import Optional

import oss2

from oss_config import oss_config
from config import get_dataset_upload_path
from database import get_database_session, FileUploadRecord
from services import notify_upload_complete

logger = logging.getLogger(__name__)


class OSSUploadService:
    """OSS 上传服务"""

    def __init__(self):
        auth = oss2.Auth(oss_config.access_key_id, oss_config.access_key_secret)
        self.bucket = oss2.Bucket(auth, oss_config.endpoint, oss_config.bucket_name)

    def get_oss_key(self, dataset_id: str, file_name: str) -> str:
        """生成 OSS 对象 key"""
        return f"{oss_config.upload_prefix}{dataset_id}/{file_name}"

    def get_credentials(self, dataset_id: str, file_name: str) -> dict:
        """返回 AK/SK 凭证供 SDK 直接上传"""
        return {
            "access_key_id": oss_config.access_key_id,
            "access_key_secret": oss_config.access_key_secret,
            "endpoint": oss_config.endpoint,
            "bucket": oss_config.bucket_name,
            "oss_key": self.get_oss_key(dataset_id, file_name),
        }

    def verify_oss_file(self, dataset_id: str, file_name: str) -> Optional[int]:
        """验证 OSS 上的文件是否存在，返回文件大小"""
        oss_key = self.get_oss_key(dataset_id, file_name)
        try:
            meta = self.bucket.head_object(oss_key)
            return meta.content_length
        except oss2.exceptions.NotFound:
            return None

    def complete_upload(self, task_id: int, dataset_id: str, file_name: str,
                        file_size: int, user_id: str, user_name: str, token_hash: str):
        """标记上传完成，记录到数据库（文件已在 OSS 上，无需传输）"""
        from database_oss import OSSUploadTask
        import asyncio

        oss_key = self.get_oss_key(dataset_id, file_name)
        oss_path = f"oss://{oss_config.bucket_name}/{oss_key}"

        db = get_database_session()
        try:
            task = db.query(OSSUploadTask).filter(OSSUploadTask.id == task_id).first()
            if not task:
                logger.error(f"OSS 任务 {task_id} 不存在")
                return

            # 更新任务状态为完成
            task.status = "completed"
            task.file_size = file_size
            task.file_path = oss_path
            task.completed_at = datetime.utcnow()
            db.commit()

            # 写入上传记录
            upload_record = FileUploadRecord(
                user_id=user_id,
                user_name=user_name,
                token_hash=token_hash,
                file_id=f"oss_{task_id}",
                file_name=file_name,
                file_size=file_size,
                file_path=oss_path,
                dataset_id=dataset_id,
                total_chunks=0,
                upload_status="completed",
                upload_completed_at=datetime.utcnow()
            )
            db.add(upload_record)
            db.commit()

            # 异步通知前端
            try:
                loop = asyncio.new_event_loop()
                loop.run_until_complete(notify_upload_complete(dataset_id, oss_path, user_id))
                loop.close()
            except Exception as e:
                logger.warning(f"上传通知失败: {e}")

            logger.info(f"OSS 任务 {task_id} 完成: {oss_path} ({file_size} bytes)")

        except Exception as e:
            logger.error(f"OSS 任务 {task_id} 完成处理失败: {e}")
            try:
                task = db.query(OSSUploadTask).filter(OSSUploadTask.id == task_id).first()
                if task:
                    task.status = "failed"
                    task.error_message = str(e)
                    db.commit()
            except Exception:
                pass
        finally:
            db.close()


oss_upload_service = OSSUploadService()
