"""
Main release manager orchestrating complete release workflows.

This module provides the primary ReleaseManager class that coordinates
all aspects of the release process.
"""

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

from .builder import PackageBuilder
from .publisher import PublishManager
from ..git.manager import GitManager
from ..utils.validation import ReleaseValidator


class ReleaseManager:
    """Main orchestrator for release workflows."""

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

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

        # Initialize component managers
        self.git_manager = GitManager(project_root, dry_run)
        self.builder = PackageBuilder(project_root, dry_run)
        self.publisher = PublishManager(project_root, dry_run)
        self.validator = ReleaseValidator(project_root)

    def get_release_status(self) -> Dict[str, Any]:
        """Get comprehensive release status information.

        Returns:
            Dictionary with release status details
        """
        status = {}

        # Version information
        status['version'] = self.builder.get_current_version()

        # Git status
        git_status = self.git_manager.get_repository_status()
        status.update(git_status)

        # Package status
        packages = self.builder.get_built_packages()
        status['packages'] = {
            'wheels': [p.name for p in packages['wheels']],
            'sdists': [p.name for p in packages['sdists']],
            'total_count': len(packages['wheels']) + len(packages['sdists'])
        }

        # Validation status
        is_valid, issues = self.validate_release_state()
        status['validation'] = {
            'is_valid': is_valid,
            'issues': issues
        }

        return status

    def validate_release_state(self) -> Tuple[bool, List[str]]:
        """Validate that the repository is ready for release.

        Returns:
            Tuple of (is_valid, list_of_issues)
        """
        return self.validator.validate_release_state(force=self.force)

    def create_tag(self, version: str, message: Optional[str] = None, push: bool = True) -> bool:
        """Create a git tag for the release.

        Args:
            version: Version to tag (e.g., "1.0.0")
            message: Optional tag message
            push: Whether to push the tag to origin (default: True)

        Returns:
            True if tag created successfully, False otherwise
        """
        # Validate release state first
        is_valid, issues = self.validate_release_state()
        if not is_valid and not self.force:
            print("❌ Cannot create tag:")
            for issue in issues:
                print(f"  - {issue}")
            return False

        # Check version-tag consistency (ensure CHANGELOG has version section)
        changelog_valid, changelog_issues = self.validator.validate_changelog_version(version)
        if not changelog_valid and not self.force:
            print(f"❌ Cannot create tag for version {version}:")
            for issue in changelog_issues:
                print(f"  - {issue}")
            print("\n💡 Tip: Add a section for version {version} to CHANGELOG.md before tagging")
            return False

        return self.git_manager.create_tag(version, message, push=push)

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

        Returns:
            True if build successful, False otherwise
        """
        success = self.builder.build_packages()
        if success:
            success = self.builder.validate_packages()
        return success

    def publish_release(self, version: str, registry_type: str = 'gitea',
                       skip_build: bool = False) -> bool:
        """Complete release workflow: validate, tag, build, and publish.

        Args:
            version: Version to release
            registry_type: Type of registry to publish to
            skip_build: If True, skip building and use existing packages

        Returns:
            True if release successful, False otherwise
        """
        print(f"🚀 Publishing release {version}")

        # Validate state
        is_valid, issues = self.validate_release_state()
        if not is_valid and not self.force:
            print("❌ Cannot publish release:")
            for issue in issues:
                print(f"  - {issue}")
            return False

        # Create git tag (this determines the version for setuptools-scm)
        if not self.git_manager.tag_exists(f"v{version}"):
            if not self.create_tag(version):
                return False
        else:
            print(f"✅ Tag v{version} already exists")

        # Build packages (setuptools-scm will use the tag for version)
        if not skip_build:
            if not self.build_packages():
                return False
        else:
            print("⏭️  Skipping build (using existing packages)")

        # Publish packages
        if not self.publisher.publish_packages(registry_type):
            print("⚠️  Release completed but publishing failed")
            return False

        print(f"✅ Release {version} completed successfully!")
        print(f"📦 Packages published to {registry_type}")
        print(f"🏷️  Git tag v{version} created")
        return True

    def publish_with_fallback(self, version: str, registry_type: str = 'gitea',
                            skip_build: bool = False) -> bool:
        """Complete release workflow with fallback to release assets.

        Args:
            version: Version to release
            registry_type: Type of registry to publish to
            skip_build: If True, skip building and use existing packages

        Returns:
            True if release successful, False otherwise
        """
        # Try normal publish first
        if self.publish_release(version, registry_type, skip_build):
            return True

        # If that fails, try release assets fallback
        print("🔄 Attempting release assets fallback...")
        return self.publisher.publish_as_release_assets(version, registry_type)

    def upload_existing_packages(self, registry_type: str = 'gitea') -> bool:
        """Upload existing packages without building or tagging.

        Args:
            registry_type: Type of registry to upload to

        Returns:
            True if upload successful, False otherwise
        """
        print(f"📤 Uploading existing packages to {registry_type}")

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

        all_packages = packages["wheels"] + packages["sdists"]
        return self.publisher.upload_specific_packages(all_packages, registry_type)

    def clean_build_artifacts(self) -> None:
        """Clean build artifacts and temporary files."""
        self.builder.clean_build()

    def show_registry_info(self, registry_type: str = 'gitea') -> Dict[str, Any]:
        """Show information about a registry.

        Args:
            registry_type: Type of registry

        Returns:
            Dictionary with registry information
        """
        return self.publisher.get_registry_info(registry_type)

    def get_commits_since_last_tag(self) -> List[str]:
        """Get commits since the last release tag.

        Returns:
            List of commit messages since last tag
        """
        return self.git_manager.get_commits_since_tag()

    def check_version_consistency(self, version: str) -> Tuple[bool, List[str]]:
        """Check consistency between CHANGELOG version and git tags.

        Args:
            version: Version to check (e.g., "0.10.0")

        Returns:
            Tuple of (is_consistent, list_of_issues)
        """
        return self.validator.check_version_tag_consistency(version)