#!/opt/rbta/venvs/aldpro-common/bin/python3

import os
import sys

BASE_DIR = "/opt/rbta/aldpro/repo"
if BASE_DIR not in sys.path:
    sys.path.insert(0, BASE_DIR)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "core.settings")
from django.core.wsgi import get_wsgi_application

get_wsgi_application()


import glob
import logging
from datetime import datetime, timedelta
from logging.handlers import SysLogHandler
from shutil import rmtree

from repository.models.repository_version import RepositoryVersion

STORAGE_PATH = "/opt/rbta/aldpro/repo/storage"
TMP_STORAGE_PATH = f"{STORAGE_PATH}/tmp"
IGNORE = (".gitkeep",)

logger = logging.getLogger("aldpro-repo-garbage-collector")
logger.setLevel(logging.ERROR)

handler = SysLogHandler(address="/dev/log")
formatter = logging.Formatter("%(name)s %(levelname)s %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)


class RepositoryGarbageCollector:
    def __init__(self, paths_ttl: timedelta = timedelta(days=1)):
        self.paths_ttl = paths_ttl

    def _is_ttl_valid(self, path: str) -> bool:
        """Проверка на установленное время жизни файла/директории

        Args:
            file_path (str): путь к файлу/директории
        Returns:
            bool: Разница между текущим временем и датой последней модификации файла/директории больше заданной или нет
        """
        return timedelta(seconds=(datetime.timestamp(datetime.now()) - os.path.getmtime(path))) < self.paths_ttl

    def _remove_version(self, version: str, repository: str) -> None:
        """Удаление версий репозитория

        Args:
            version (str): путь к версии
            repository (str): путь к репозиторию
        """
        repository_name = repository.split("/")[-1]
        version_name = version.split("/")[-1]
        logger.info(f"Найдена неактивная версия {version_name} в репозитории {repository_name}")

        if os.path.exists(version):
            rmtree(version)
            logger.info(f"Неактивная версия {version_name} удалена из {repository}")
        mount_version = STORAGE_PATH + f"/{repository_name}/{version_name}"
        if os.path.exists(mount_version):
            rmtree(mount_version)
            logger.info(f"Неактивная версия {version_name} удалена из {STORAGE_PATH}/{repository_name}")

        instance = RepositoryVersion.objects.filter(
            repositoryversion_repository_id=repository_name,
            repositoryversion_id=version_name,
            repositoryversion_status="edit",
        ).first()
        if instance:
            instance.delete()
            logger.info(f"Неактивная версия {version_name} удалена из базы данных")

    def _remove_repository(self, repository: str) -> None:
        """Удаление репозиторея

        Args:
            repository (str): путь к репозиторию
        """
        repository_name = repository.split("/")[-1]
        if len(os.listdir(repository)) == 0:
            rmtree(repository)
            logger.info(f"Удален пустой временный репозиторий: {repository_name}")

    def run(self):
        """Запуск сборщика мусора"""
        logger.info("Начата проверка мусорных файлов сервера репозитория")

        if not os.path.exists(TMP_STORAGE_PATH):
            logger.error(f"Директория {TMP_STORAGE_PATH} не существует")
            return

        for repository in glob.iglob(f"{TMP_STORAGE_PATH}/*"):
            if os.path.isdir(repository) and not repository.endswith(IGNORE):
                logger.info(f"Найден временный репозиторий: {repository}")
                for version in glob.iglob(f"{repository}/*"):
                    if not self._is_ttl_valid(version):
                        self._remove_version(version, repository)
                self._remove_repository(repository)


if __name__ == "__main__":
    garbage_collector = RepositoryGarbageCollector()
    garbage_collector.run()
