"""
Package building functionality for releases.

This module handles package building using setuptools-scm and the Python build module.
"""

import subprocess
import sys
from pathlib import Path
from typing import List, Optional, Dict, Any

from ..utils.version import VersionManager


class PackageBuilder:
    """Handles package building with setuptools-scm integration."""

    def __init__(self, project_root: Optional[Path] = None, dry_run: bool = False):
        """Initialize the package builder.

        Args:
            project_root: Root directory of the project. Defaults to current directory.
            dry_run: If True, show what would be done without executing.
        """
        self.project_root = project_root or Path.cwd()
        self.dry_run = dry_run
        self.dist_dir = self.project_root / "dist"

    def get_current_version(self) -> str:
        """Get current version using setuptools-scm.

        Returns:
            Current version string or "unknown" if unavailable.
        """
        try:
            result = self._run_command(
                ['python', '-m', 'setuptools_scm'],
                capture=True,
                skip_dry_run=True
            )
            return result.stdout.strip()
        except subprocess.CalledProcessError:
            return "unknown"

    def clean_build(self) -> None:
        """Clean previous build artifacts."""
        print("🧹 Cleaning build artifacts...")

        patterns = ['build', 'dist', '*.egg-info']
        for pattern in patterns:
            try:
                if pattern == 'dist' and self.dist_dir.exists():
                    if self.dry_run:
                        print(f"[DRY RUN] Would remove: {self.dist_dir}")
                    else:
                        import shutil
                        shutil.rmtree(self.dist_dir)
                        print(f"✅ Removed: {self.dist_dir}")
                elif pattern != 'dist':
                    self._run_command(['rm', '-rf', pattern])
            except subprocess.CalledProcessError:
                pass  # Ignore if files don't exist

    def build_packages(self) -> bool:
        """Build release packages using setuptools-scm.

        Returns:
            True if build successful, False otherwise.
        """
        print(f"📦 Building packages (version auto-determined by setuptools-scm)")

        # Clean previous builds
        self.clean_build()

        # Build packages
        try:
            print("Building packages...")
            self._run_command(['python', '-m', 'build'], capture=False)
            print("✅ Packages built successfully")

            # Show package details
            self._show_package_details()
            return True

        except subprocess.CalledProcessError as e:
            print(f"❌ Package build failed: {e}")
            return False

    def get_built_packages(self) -> Dict[str, List[Path]]:
        """Get list of built packages by type.

        Returns:
            Dictionary with 'wheels' and 'sdists' keys containing file paths.
        """
        if not self.dist_dir.exists():
            return {"wheels": [], "sdists": []}

        wheels = list(self.dist_dir.glob("*.whl"))
        sdists = list(self.dist_dir.glob("*.tar.gz"))

        return {"wheels": wheels, "sdists": sdists}

    def validate_packages(self) -> bool:
        """Validate that expected packages were built.

        Returns:
            True if packages are valid, False otherwise.
        """
        packages = self.get_built_packages()

        if not packages["wheels"] and not packages["sdists"]:
            print("❌ No packages found in dist/")
            return False

        # Check package sizes
        for wheel in packages["wheels"]:
            if wheel.stat().st_size < 1000:  # Less than 1KB
                print(f"⚠️  Warning: {wheel.name} is very small ({wheel.stat().st_size} bytes)")

        for sdist in packages["sdists"]:
            if sdist.stat().st_size < 1000:  # Less than 1KB
                print(f"⚠️  Warning: {sdist.name} is very small ({sdist.stat().st_size} bytes)")

        return True

    def _show_package_details(self) -> None:
        """Show details about built packages."""
        packages = self.get_built_packages()

        if packages["wheels"] or packages["sdists"]:
            print(f"\n📦 Built packages in {self.dist_dir}:")

            for wheel in packages["wheels"]:
                size = wheel.stat().st_size
                print(f"  🎯 {wheel.name} ({size:,} bytes)")

            for sdist in packages["sdists"]:
                size = sdist.stat().st_size
                print(f"  📄 {sdist.name} ({size:,} bytes)")
        else:
            print("❌ No packages found")

    def _run_command(self, cmd: List[str], capture: bool = True,
                    check: bool = True, skip_dry_run: bool = False) -> subprocess.CompletedProcess:
        """Run a command with optional dry-run support.

        Args:
            cmd: Command to execute
            capture: Whether to capture output
            check: Whether to raise on non-zero exit
            skip_dry_run: Whether to skip dry-run check and always execute

        Returns:
            CompletedProcess result
        """
        if self.dry_run and not skip_dry_run:
            print(f"[DRY RUN] Would run: {' '.join(cmd)}")
            return subprocess.CompletedProcess(cmd, 0, "", "")

        return subprocess.run(
            cmd,
            capture_output=capture,
            text=True,
            check=check,
            cwd=self.project_root
        )