"""Archive extraction operation."""

from __future__ import annotations

import shutil
import tempfile
from pathlib import Path
from typing import Any

from cascade_fm.core.cache.cache_artifact import ArtifactCacheMixin
from cascade_fm.operations.base import Operation


class Unarchive(ArtifactCacheMixin, Operation):
    """Extract archive files into a temporary output directory."""

    @property
    def name(self) -> str:
        return "unarchive"

    @property
    def label(self) -> str:
        return "Unarchive"

    @property
    def description(self) -> str:
        return "Extract ZIP/TAR archives into folders"

    @property
    def accepts(self) -> list[str]:
        return [
            "application/zip",
            "application/x-tar",
            "application/x-gtar",
            "application/gzip",
            "application/x-gzip",
            "application/x-bzip",
            "application/x-bzip2",
            "application/x-xz",
        ]

    def _can_execute_without_params(self) -> bool:
        return True

    def _execute_impl(self, files: list[Path], **params: Any) -> list[Path]:
        flatten_single_root = bool(params.get("flatten_single_root", True))

        output_root = Path(tempfile.mkdtemp(prefix="cascade_unarchive_"))
        extracted_entries: list[Path] = []
        archive_files = [archive_path for archive_path in files if archive_path.is_file()]
        total = len(archive_files)

        for index, archive_path in enumerate(archive_files, start=1):
            self.report_progress(index - 1, total, f"Extracting {archive_path.name}")

            archive_output_dir = output_root / archive_path.stem
            archive_output_dir.mkdir(parents=True, exist_ok=True)

            shutil.unpack_archive(str(archive_path), str(archive_output_dir))

            top_level_entries = sorted(archive_output_dir.iterdir(), key=lambda p: p.name.lower())
            if (
                flatten_single_root
                and len(top_level_entries) == 1
                and top_level_entries[0].is_dir()
            ):
                top_level_entries = sorted(
                    top_level_entries[0].iterdir(), key=lambda p: p.name.lower()
                )

            extracted_entries.extend(top_level_entries)
            self.report_progress(index, total, f"Extracted {archive_path.name}")

        if total > 0:
            self.report_progress(total, total, "Unarchive complete")

        return extracted_entries

    def validate_params(self, **params: Any) -> tuple[bool, str | None]:
        flatten_single_root = params.get("flatten_single_root")
        if flatten_single_root is not None and not isinstance(flatten_single_root, bool):
            return False, "flatten_single_root must be a boolean"
        return True, None
