"""
Package publishing functionality for releases.

This module handles publishing packages to various registries.
"""

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

from ..registries.factory import RegistryFactory
from ..registries.base import RegistryInterface
from .builder import PackageBuilder


class PublishManager:
    """Handles package publication to registries."""

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

        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

    def publish_packages(self, registry_type: str = 'gitea',
                        registry_config: Optional[Dict[str, Any]] = None) -> bool:
        """Publish packages to specified registry.

        Args:
            registry_type: Type of registry to publish to
            registry_config: Optional registry configuration

        Returns:
            True if publishing successful, False otherwise
        """
        try:
            # Get registry client
            registry = self._get_registry(registry_type, registry_config)

            # Get built packages
            builder = PackageBuilder(self.project_root)
            packages = builder.get_built_packages()

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

            # Upload packages
            success = True
            for wheel in packages["wheels"]:
                if not self._upload_package_with_fallback(registry, wheel):
                    success = False

            for sdist in packages["sdists"]:
                if not self._upload_package_with_fallback(registry, sdist):
                    success = False

            return success

        except Exception as e:
            print(f"❌ Publishing failed: {e}")
            return False

    def upload_specific_packages(self, package_paths: List[Path],
                               registry_type: str = 'gitea',
                               registry_config: Optional[Dict[str, Any]] = None) -> bool:
        """Upload specific package files to registry.

        Args:
            package_paths: List of paths to package files
            registry_type: Type of registry to publish to
            registry_config: Optional registry configuration

        Returns:
            True if all uploads successful, False otherwise
        """
        try:
            registry = self._get_registry(registry_type, registry_config)

            success = True
            for package_path in package_paths:
                if not package_path.exists():
                    print(f"❌ Package not found: {package_path}")
                    success = False
                    continue

                if not self._upload_package_with_fallback(registry, package_path):
                    success = False

            return success

        except Exception as e:
            print(f"❌ Upload failed: {e}")
            return False

    def publish_as_release_assets(self, version: str,
                                registry_type: str = 'gitea',
                                registry_config: Optional[Dict[str, Any]] = None) -> bool:
        """Publish packages as release assets (fallback method).

        Args:
            version: Version to publish as
            registry_type: Type of registry (must support release assets)
            registry_config: Optional registry configuration

        Returns:
            True if publishing successful, False otherwise
        """
        try:
            registry = self._get_registry(registry_type, registry_config)

            # Check if registry supports release assets
            if not hasattr(registry, 'upload_package_as_release_assets'):
                print(f"❌ Registry type '{registry_type}' does not support release assets")
                return False

            # Get built packages
            builder = PackageBuilder(self.project_root)
            packages = builder.get_built_packages()

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

            # Find wheel and corresponding source distribution
            success = True
            for wheel in packages["wheels"]:
                # Find matching sdist
                sdist = None
                wheel_name_parts = wheel.stem.split('-')
                package_name = wheel_name_parts[0] if wheel_name_parts else ""

                for potential_sdist in packages["sdists"]:
                    if potential_sdist.stem.startswith(package_name):
                        sdist = potential_sdist
                        break

                # Upload as release assets
                if not registry.upload_package_as_release_assets(
                    version, wheel, sdist, dry_run=self.dry_run
                ):
                    success = False

            return success

        except Exception as e:
            print(f"❌ Release asset publishing failed: {e}")
            return False

    def get_registry_info(self, registry_type: str = 'gitea',
                         registry_config: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """Get information about a registry.

        Args:
            registry_type: Type of registry
            registry_config: Optional registry configuration

        Returns:
            Dictionary with registry information
        """
        try:
            registry = self._get_registry(registry_type, registry_config)
            return registry.get_registry_info()
        except Exception as e:
            return {"error": str(e)}

    def _get_registry(self, registry_type: str,
                     registry_config: Optional[Dict[str, Any]] = None) -> RegistryInterface:
        """Get a registry client.

        Args:
            registry_type: Type of registry
            registry_config: Optional registry configuration

        Returns:
            Registry client instance
        """
        if registry_config:
            return RegistryFactory.create(registry_type, registry_config)
        else:
            # Try to load from pyproject.toml first
            try:
                return RegistryFactory.create_from_pyproject_config(
                    self.project_root / "pyproject.toml",
                    registry_type
                )
            except (ValueError, FileNotFoundError):
                # Fallback to auto-detection
                return RegistryFactory.create(registry_type)

    def _upload_package_with_fallback(self, registry: RegistryInterface,
                                    package_path: Path) -> bool:
        """Upload a package with fallback to release assets if needed.

        Args:
            registry: Registry client
            package_path: Path to package file

        Returns:
            True if upload successful, False otherwise
        """
        try:
            # Try normal package upload first
            return registry.upload_package(package_path, dry_run=self.dry_run)
        except Exception as e:
            print(f"⚠️  Package upload failed: {e}")

            # Check if registry supports release assets as fallback
            if hasattr(registry, 'upload_package_as_release_assets'):
                print("🔄 Trying release assets as fallback...")

                # Extract version from package filename for release assets
                version = self._extract_version_from_filename(package_path)
                if version:
                    return registry.upload_package_as_release_assets(
                        version, package_path, dry_run=self.dry_run
                    )

            return False

    def _extract_version_from_filename(self, package_path: Path) -> Optional[str]:
        """Extract version from package filename.

        Args:
            package_path: Path to package file

        Returns:
            Version string or None if not found
        """
        try:
            if package_path.suffix == '.whl':
                # Wheel format: package-version-python-abi-platform.whl
                parts = package_path.stem.split('-')
                if len(parts) >= 2:
                    return parts[1]
            elif package_path.suffix == '.gz' and package_path.name.endswith('.tar.gz'):
                # Source dist format: package-version.tar.gz
                name_without_tar = package_path.name.replace('.tar.gz', '')
                parts = name_without_tar.split('-')
                if len(parts) >= 2:
                    return parts[1]
        except Exception:
            pass

        return None