"""Publish command implementation for MakePython."""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from ...core.executor import execute_command_with_context
from ...interfaces.command import CommandResult, CommandType, ValidatableCommand
from .token import TOKEN_FILE
from .version import bump_version_command

if TYPE_CHECKING:
    from ...core.context import ExecutionContext


class PublishCommand(ValidatableCommand):
    """Publish package to PyPI with cleanup and git operations."""

    name = "publish"
    alias = "p"
    description = "Publish package to PyPI with cleanup and git operations"
    command_type = CommandType.PUBLISH

    def validate(self, context: ExecutionContext) -> bool:
        """Validate publish command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Check if pyproject.toml exists
        pyproject_path = context.cwd / "pyproject.toml"
        if not pyproject_path.exists():
            self.logger.error("pyproject.toml not found in current directory")
            return False

        # Check if build tool is available
        build_tool = context.get_build_tool()
        if not build_tool:
            self.logger.error("Could not determine build tool from pyproject.toml")
            return False

        # Check if PyPI token is configured
        if not self.check_pypi_token():
            self.logger.warning("PyPI token not configured")
            self.logger.info("Please run 'makepython token' to configure your PyPI token")
            return False

        return True

    def _git_operations(self, context: ExecutionContext) -> None:
        """Perform git operations after publish.

        Args:
            context: Execution context
        """
        try:
            # Check if we're in a git repository
            result = execute_command_with_context(["git", "rev-parse", "--git-dir"], context)

            if result.success:
                self.logger.info("Pushing changes to remote repository...")

                # Push all branches and tags
                push_result = execute_command_with_context(["git", "push", "--all"], context)
                if not push_result.success:
                    self.logger.warning("Git push failed")

                push_tags = execute_command_with_context(["git", "push", "--tags"], context)
                if not push_tags.success:
                    self.logger.warning("Git push tags failed")
            else:
                self.logger.debug("Not a git repository, skipping git operations")

        except Exception as e:
            self.logger.warning(f"Git operations failed: {e}")

    def execute(self, context: ExecutionContext) -> CommandResult:
        """Execute publish command.

        Args:
            context: Execution context

        Returns
        -------
            CommandResult with execution status
        """
        if not self.validate(context):
            return CommandResult(success=False, message="Validation failed")

        try:
            build_tool = context.get_build_tool()
            if not build_tool:
                return CommandResult(success=False, message="Could not determine build tool")

            self.logger.info(f"Publishing package using {build_tool.value}...")

            # Get PyPI token
            self.get_pypi_token()

            # Execute publish command based on build tool
            if build_tool.value == "hatch":
                cmd = ["hatch", "publish"]
            elif build_tool.value == "poetry":
                cmd = ["poetry", "publish"]
            else:  # uv
                cmd = ["uv", "publish"]

            result = execute_command_with_context(cmd, context)

            if result.success:
                self.logger.info("Package published successfully!")

                # Perform git operations
                self._git_operations(context)

                return CommandResult(success=True, message="Package published successfully")
            self.logger.error(f"Publish failed with exit code {result.exit_code}")
            return CommandResult(success=False, message=f"Publish failed: {result.message}")

        except Exception as e:
            self.logger.exception(f"Publish failed: {e}")
            return CommandResult(success=False, message=str(e))

    def get_pypi_token(self) -> str | None:
        """Get PyPI token from .pypirc configuration.

        Returns
        -------
            Token string if configured, None otherwise
        """
        if not TOKEN_FILE.exists():
            return None

        try:
            import configparser

            config = configparser.ConfigParser()
            config.read(TOKEN_FILE, encoding="utf-8")

            # Try to get token from pypi section
            if "pypi" in config and "password" in config["pypi"]:
                return config["pypi"]["password"]

            # Try pypi.org section
            if "pypi.org" in config and "password" in config["pypi.org"]:
                return config["pypi.org"]["password"]

            return None
        except Exception:
            self.logger.warning("Failed to load PyPI token from .pypirc")
            return None

    def check_pypi_token(self) -> bool:
        """Check if PyPI token is configured.

        Returns
        -------
            True if token exists, False otherwise
        """
        if not TOKEN_FILE.exists():
            return False

        token = self.get_pypi_token()
        return bool(token)


class BumpPublishCommand(ValidatableCommand):
    """Bump version and publish project."""

    name = "bump-publish"
    alias = "bp"
    description = "Bump version and publish project"
    command_type = CommandType.PUBLISH

    def __init__(self):
        """Initialize the bump-publish command."""
        self.logger = logging.getLogger(__name__)

    def validate(self, context: ExecutionContext) -> bool:
        """Validate bump-publish command prerequisites.

        Args:
            context: Execution context

        Returns
        -------
            True if validation passes, False otherwise
        """
        # Check if pyproject.toml exists
        pyproject_path = context.cwd / "pyproject.toml"
        if not pyproject_path.exists():
            self.logger.error("pyproject.toml not found")
            return False

        # Check if build tool is available
        build_tool = context.get_build_tool()
        if not build_tool:
            self.logger.error("Could not determine build tool")
            return False

        return True

    def execute(self, context: ExecutionContext) -> CommandResult:
        """Execute bump and publish command.

        Args:
            context: Execution context

        Returns
        -------
            CommandResult with execution status
        """
        if not self.validate(context):
            return CommandResult(success=False, message="Validation failed")

        try:
            self.logger.info("Bumping patch version...")
            bump_result = bump_version_command(context, "patch")

            if not bump_result.success:
                self.logger.error("Version bump failed")
                return bump_result

            # Build the project
            build_tool = context.get_build_tool()
            if not build_tool:
                return CommandResult(success=False, message="Could not determine build tool")

            self.logger.info("Building project...")
            build_cmd = [build_tool.value, "build"]
            build_result = execute_command_with_context(build_cmd, context)

            if not build_result.success:
                self.logger.error("Build failed")
                return build_result

            # Publish the project
            publish_cmd = PublishCommand()
            publish_result = publish_cmd.execute(context)

            if publish_result.success:
                self.logger.info("Version bumped, built, and published successfully!")
                return CommandResult(success=True, message="Version bumped, built, and published")
            return publish_result

        except Exception as e:
            self.logger.exception(f"Bump-publish failed: {e}")
            return CommandResult(success=False, message=str(e))
