"""
XCResult cache management.

Handles storage, retrieval, and lifecycle of xcresult bundles for progressive disclosure.
"""

import shutil
from datetime import datetime
from pathlib import Path


class XCResultCache:
    """
    Manage xcresult bundle cache for progressive disclosure.

    Stores xcresult bundles with timestamp-based IDs and provides
    retrieval and cleanup operations.
    """

    # Default cache directory
    DEFAULT_CACHE_DIR = Path.home() / ".ios-simulator-skill" / "xcresults"

    def __init__(self, cache_dir: Path | None = None):
        """
        Initialize cache manager.

        Args:
            cache_dir: Custom cache directory (uses default if not specified)
        """
        self.cache_dir = cache_dir or self.DEFAULT_CACHE_DIR
        self.cache_dir.mkdir(parents=True, exist_ok=True)

    def generate_id(self, prefix: str = "xcresult") -> str:
        """
        Generate timestamped xcresult ID.

        Args:
            prefix: ID prefix (default: "xcresult")

        Returns:
            ID string like "xcresult-20251018-143052"
        """
        timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
        return f"{prefix}-{timestamp}"

    def get_path(self, xcresult_id: str) -> Path:
        """
        Get full path for xcresult ID.

        Args:
            xcresult_id: XCResult ID

        Returns:
            Path to xcresult bundle
        """
        # Handle both with and without .xcresult extension
        if xcresult_id.endswith(".xcresult"):
            return self.cache_dir / xcresult_id
        return self.cache_dir / f"{xcresult_id}.xcresult"

    def exists(self, xcresult_id: str) -> bool:
        """
        Check if xcresult bundle exists.

        Args:
            xcresult_id: XCResult ID

        Returns:
            True if bundle exists
        """
        return self.get_path(xcresult_id).exists()

    def save(self, source_path: Path, xcresult_id: str | None = None) -> str:
        """
        Save xcresult bundle to cache.

        Args:
            source_path: Source xcresult bundle path
            xcresult_id: Optional custom ID (generates if not provided)

        Returns:
            xcresult ID
        """
        if not source_path.exists():
            raise FileNotFoundError(f"Source xcresult not found: {source_path}")

        # Generate ID if not provided
        if not xcresult_id:
            xcresult_id = self.generate_id()

        # Get destination path
        dest_path = self.get_path(xcresult_id)

        # Copy xcresult bundle (it's a directory)
        if dest_path.exists():
            shutil.rmtree(dest_path)

        shutil.copytree(source_path, dest_path)

        return xcresult_id

    def list(self, limit: int = 10) -> list[dict]:
        """
        List recent xcresult bundles.

        Args:
            limit: Maximum number to return

        Returns:
            List of xcresult metadata dicts
        """
        if not self.cache_dir.exists():
            return []

        results = []
        for path in sorted(
            self.cache_dir.glob("*.xcresult"), key=lambda p: p.stat().st_mtime, reverse=True
        )[:limit]:
            # Calculate bundle size
            size_bytes = sum(f.stat().st_size for f in path.rglob("*") if f.is_file())

            results.append(
                {
                    "id": path.stem,
                    "path": str(path),
                    "created": datetime.fromtimestamp(path.stat().st_mtime).isoformat(),
                    "size_mb": round(size_bytes / (1024 * 1024), 2),
                }
            )

        return results

    def cleanup(self, keep_recent: int = 20) -> int:
        """
        Clean up old xcresult bundles.

        Args:
            keep_recent: Number of recent bundles to keep

        Returns:
            Number of bundles removed
        """
        if not self.cache_dir.exists():
            return 0

        # Get all bundles sorted by modification time
        all_bundles = sorted(
            self.cache_dir.glob("*.xcresult"), key=lambda p: p.stat().st_mtime, reverse=True
        )

        # Remove old bundles
        removed = 0
        for bundle_path in all_bundles[keep_recent:]:
            shutil.rmtree(bundle_path)
            removed += 1

        return removed

    def get_size_mb(self, xcresult_id: str) -> float:
        """
        Get size of xcresult bundle in MB.

        Args:
            xcresult_id: XCResult ID

        Returns:
            Size in MB
        """
        path = self.get_path(xcresult_id)
        if not path.exists():
            return 0.0

        size_bytes = sum(f.stat().st_size for f in path.rglob("*") if f.is_file())
        return round(size_bytes / (1024 * 1024), 2)

    def save_stderr(self, xcresult_id: str, stderr: str) -> None:
        """
        Save stderr output alongside xcresult bundle.

        Args:
            xcresult_id: XCResult ID
            stderr: stderr output from xcodebuild
        """
        if not stderr:
            return

        stderr_path = self.cache_dir / f"{xcresult_id}.stderr"
        stderr_path.write_text(stderr, encoding="utf-8")

    def get_stderr(self, xcresult_id: str) -> str:
        """
        Retrieve cached stderr output.

        Args:
            xcresult_id: XCResult ID

        Returns:
            stderr content or empty string if not found
        """
        stderr_path = self.cache_dir / f"{xcresult_id}.stderr"
        if not stderr_path.exists():
            return ""

        return stderr_path.read_text(encoding="utf-8")
