from typing import List

from miniopy_async.datatypes import Object as MinioObject
from datetime import datetime, timedelta
from loguru import logger

from huibiao_framework.client import MinIOClient
from huibiao_framework.config import MinioConfig


class OssOutdatedDirCleaner:
    """
    删除oss中过期的目录
    """

    def __init__(self, prefix: str, client: MinIOClient, retention_day: int = 30, theme: str = ""):
        self.prefix = prefix
        self.retention_day = retention_day
        self.theme = theme
        self.current_time: datetime = datetime.now()
        self.threshold_time: datetime = self.current_time - timedelta(
            days=self.retention_day
        )
        self.client: MinIOClient = client

    def thread_hold_time(self):
        return self.threshold_time

    async def do_clean(self):
        """
        开始清除
        """
        outdated_objs = await self.list_outdated_obj()
        logger.info(f"{self.theme} 开始清理缓存目录，共{len(outdated_objs)}个目录")
        failed = await self.batch_delete_obj(obj_list=outdated_objs, client=self.client)
        logger.info(f"{self.theme} 缓存目录清理完成，失败数{len(failed)}/{len(outdated_objs)}")


    def is_outdated(self, obj: MinioObject):
        if obj.object_name == self.prefix or obj.last_modified is None:
            return False
        return obj.last_modified < self.threshold_time

    async def list_outdated_obj(self) -> List[MinioObject]:
        """
        列出过期的oss key
        """
        result: List[MinioObject] = await self.client.list_objects(
            bucket_name=MinioConfig.BUCKET_NAME, prefix=self.prefix
        )
        outdated_obj_list = [r for r in result if self.is_outdated(r)]

        logger.debug(
            f"path={self.prefix}, threshold_time={self.threshold_time}, "
            f"retention_day={self.retention_day}, found outdated obj, {len(outdated_obj_list)}"
        )

        return outdated_obj_list

    @classmethod
    async def batch_delete_obj(cls, client: MinIOClient, obj_list: List[MinioObject]) -> List[MinioObject]:
        """
        批量并递归删除目录
        返回递归删除失败的对象
        """
        num = len(obj_list)
        failed = []
        for idx, obj in enumerate(obj_list):
            logger.debug(
                f"try to delete oss key [{idx + 1}]/[{num}]: {obj.object_name}"
            )
            try:
                errors = await client.remove_objects_by_prefix_recursive(
                    MinioConfig.BUCKET_NAME, obj.object_name
                )
                if errors:
                    logger.warning(
                        f"clean unclaimed oss key [{idx}]/[{num}]: {obj.object_name} exists error: {errors}"
                    )
                    failed.append(obj)
            except Exception as e:
                logger.error(
                    f"clean unclaimed oss key [{idx}]/[{num}]: {obj.object_name} error: {e}"
                )
                failed.append(obj)

        return failed