"""Clean-Service: Findet und entfernt Nicht-Video-Dateien aus der Bibliothek"""
import logging
import os
from pathlib import Path
from typing import Optional

from app.config import Config
from app.services.library import LibraryService, VIDEO_EXTENSIONS


class CleanerService:
    """Scannt Library-Ordner nach Nicht-Video-Dateien und bietet Cleanup an"""

    def __init__(self, config: Config, library_service: LibraryService):
        self.config = config
        self.library = library_service

    @property
    def _cleanup_config(self) -> dict:
        return self.config.settings.get("cleanup", {})

    @property
    def _keep_extensions(self) -> set:
        """Extensions die behalten werden sollen"""
        exts = self._cleanup_config.get("keep_extensions", [])
        return {e.lower() for e in exts}

    async def scan_for_junk(self, library_path_id: int = None) -> dict:
        """Scannt Library-Ordner nach Nicht-Video-Dateien.
        Gibt zurueck: files, total_size, total_count"""
        paths = await self.library.get_paths()
        if library_path_id:
            paths = [p for p in paths if p["id"] == library_path_id]

        keep_exts = self._keep_extensions
        junk_files = []
        total_size = 0

        for lib_path in paths:
            if not lib_path.get("enabled"):
                continue
            base = lib_path["path"]
            if not os.path.isdir(base):
                continue

            for root, dirs, files in os.walk(base):
                # Versteckte Ordner ueberspringen
                dirs[:] = [d for d in dirs if not d.startswith(".")]
                for f in files:
                    ext = os.path.splitext(f)[1].lower()
                    # Video-Dateien und Keep-Extensions ueberspringen
                    if ext in VIDEO_EXTENSIONS:
                        continue
                    if ext in keep_exts:
                        continue

                    fp = os.path.join(root, f)
                    try:
                        size = os.path.getsize(fp)
                    except OSError:
                        size = 0

                    # Relativen Pfad berechnen
                    rel = os.path.relpath(fp, base)
                    # Serien-Ordner aus erstem Pfadteil
                    parts = rel.replace("\\", "/").split("/")
                    parent_series = parts[0] if len(parts) > 1 else ""

                    junk_files.append({
                        "path": fp,
                        "name": f,
                        "size": size,
                        "extension": ext,
                        "parent_series": parent_series,
                        "library_name": lib_path["name"],
                    })
                    total_size += size

        return {
            "files": junk_files,
            "total_size": total_size,
            "total_count": len(junk_files),
        }

    async def delete_files(self, file_paths: list[str]) -> dict:
        """Loescht die angegebenen Dateien"""
        deleted = 0
        failed = 0
        freed = 0
        errors = []

        # Sicherheitscheck: Nur Dateien in Library-Pfaden loeschen
        paths = await self.library.get_paths()
        allowed_prefixes = [p["path"] for p in paths]

        for fp in file_paths:
            # Pruefen ob Datei in erlaubtem Pfad liegt
            is_allowed = any(
                fp.startswith(prefix + "/") or fp == prefix
                for prefix in allowed_prefixes
            )
            if not is_allowed:
                errors.append(f"Nicht erlaubt: {fp}")
                failed += 1
                continue

            try:
                size = os.path.getsize(fp)
                os.remove(fp)
                deleted += 1
                freed += size
                logging.info(f"Clean: Geloescht: {fp}")
            except OSError as e:
                errors.append(f"{fp}: {e}")
                failed += 1

        return {
            "deleted": deleted,
            "failed": failed,
            "freed_bytes": freed,
            "errors": errors,
        }

    async def delete_empty_dirs(self,
                                library_path_id: int = None) -> int:
        """Leere Unterordner loeschen (bottom-up)"""
        paths = await self.library.get_paths()
        if library_path_id:
            paths = [p for p in paths if p["id"] == library_path_id]

        removed = 0
        for lib_path in paths:
            if not lib_path.get("enabled"):
                continue
            base = lib_path["path"]
            if not os.path.isdir(base):
                continue

            # Bottom-up: Tiefste Ordner zuerst
            for root, dirs, files in os.walk(base, topdown=False):
                # Nicht den Basis-Ordner selbst loeschen
                if root == base:
                    continue
                # Versteckte Ordner ueberspringen
                if os.path.basename(root).startswith("."):
                    continue
                try:
                    if not os.listdir(root):
                        os.rmdir(root)
                        removed += 1
                        logging.info(f"Clean: Leerer Ordner entfernt: {root}")
                except OSError:
                    pass

        return removed
