from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import List, Dict, Optional, Tuple
from .types import InterceptorType

from safety.meta import get_version


@dataclass
class Tool:
    name: str
    binary_names: List[str]


# TODO: Add Event driven output and support --safety-ping flag to test the
# interceptors status.
class CommandInterceptor(ABC):
    """
    Abstract base class for command interceptors.
    This class provides a framework for installing and removing interceptors
    for various tools. Subclasses must implement the `_batch_install_tools`
    and `_batch_remove_tools` methods to handle the actual installation and
    removal processes.

    Attributes:
        interceptor_type (InterceptorType): The type of the interceptor.
        tools (Dict[str, Tool]): A dictionary mapping tool names to Tool
                                 objects.
    Note:
        All method implementations should be idempotent.
    """

    def __init__(self, interceptor_type: InterceptorType):
        self.interceptor_type = interceptor_type
        self.tools: Dict[str, Tool] = {
            "pip": Tool(
                "pip", ["pip", "pip3"] + [f"pip3.{ver}" for ver in range(8, 15)]
            ),
            "poetry": Tool("poetry", ["poetry"]),
            "uv": Tool("uv", ["uv"]),
            "npm": Tool("npm", ["npm"]),
        }

    @abstractmethod
    def _batch_install_tools(self, tools: List[Tool]) -> bool:
        """
        Install multiple tools at once. Must be implemented by subclasses.
        """
        pass

    @abstractmethod
    def _batch_remove_tools(self, tools: List[Tool]) -> bool:
        """
        Remove multiple tools at once. Must be implemented by subclasses.
        """
        pass

    def install_interceptors(self, tools: Optional[List[str]] = None) -> bool:
        """
        Install interceptors for the specified tools or all tools if none
        specified.
        """
        tools_to_install = self._get_tools(tools)
        return self._batch_install_tools(tools_to_install)

    def remove_interceptors(self, tools: Optional[List[str]] = None) -> bool:
        """
        Remove interceptors for the specified tools or all tools if none
        specified.
        """
        tools_to_remove = self._get_tools(tools)
        return self._batch_remove_tools(tools_to_remove)

    def _get_tools(self, tools: Optional[List[str]] = None) -> List[Tool]:
        """
        Get list of Tool objects based on tool names.
        """
        if tools is None:
            return list(self.tools.values())
        return [self.tools[name] for name in tools if name in self.tools]

    def _generate_metadata_content(self, prepend: str) -> Tuple[str, str, str]:
        """
        Create metadata for the files that are managed by us.
        """
        return (
            f"{prepend} DO NOT EDIT THIS FILE DIRECTLY",
            f"{prepend} Last updated at: {datetime.now(timezone.utc).isoformat()}",
            f"{prepend} Updated by: safety v{get_version()}",
        )
