import os
import traceback
from typing import List

from loguru import logger

from huibiao_framework.utils.file_info_utils import DirectoryInfo, LocalAbstractFileInfo
from datetime import datetime, timedelta


class LocalOutdatedDirCleaner:
    """
    指定一个父目录，清理该目录下的过期目录，可以指定一个过期时间
    """

    def __init__(self, path: str, retention_day: int = 30, theme: str = ""):
        self.path = path
        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)

    def do_clean(self):
        """
        开始清除
        """
        outdated_dirs = self.search_unused_directory()
        logger.info(f"{self.theme} 开始清理缓存目录，共{len(outdated_dirs)}个目录")
        failed = self.batch_delete_file(outdated_dirs)
        logger.info(f"{self.theme} 缓存目录清理完成，失败数{len(failed)}/{len(outdated_dirs)}")

    def is_outdated(self, directory: DirectoryInfo) -> bool:
        """
        可以通过覆盖此类，实现定制功能
        """
        return (
            directory.access_time < self.threshold_time
            and directory.modify_time < self.threshold_time
            and directory.modify_time < self.threshold_time
        )

    def search_unused_directory(self) -> List[DirectoryInfo]:
        """
        在指定目录下搜索长时间不用的文件夹
        """

        if not os.path.exists(self.path):
            return []

        dir_list = [os.path.join(self.path, d) for d in os.listdir(self.path)]

        dir_list = [
            DirectoryInfo(d)
            for d in dir_list
            if os.path.isdir(d)
        ]

        result = [d for d in dir_list if self.is_outdated(d)]

        logger.debug(f"path={self.path}, threshold_time={self.threshold_time}, retention_day={self.retention_day}, found outdated dir, {len(result)}")

        return result

    @classmethod
    def batch_delete_file(cls, files: List[LocalAbstractFileInfo]) -> List[LocalAbstractFileInfo]:
        """
        批量删除文件
        返回删除失败的文件
        """
        if not files:
            return []
        failed: List[LocalAbstractFileInfo] = []
        num = len(files)
        for idx, f in enumerate(files):
            try:
                f.delete()
                logger.debug(f"[{idx + 1}]/[{num}] delete file {f.path} success")
            except Exception as e:
                logger.error(f"[{idx + 1}]/[{num}] delete file {f.path} failed, {e}, {traceback.format_exc()}")
                failed.append(f)
        return failed