"""
Base automation class that all third-party automations must extend.

This module provides the abstract base class that defines the interface
for automations. Developers extend this class to create custom automations
that can be submitted to the ToRivers marketplace.
"""

from abc import ABC, abstractmethod
from typing import Any, Generic, TypeVar

from langgraph.graph import StateGraph

from torivers_sdk.automation.metadata import AutomationMetadata
from torivers_sdk.automation.state import BaseState

S = TypeVar("S", bound=BaseState)


class Automation(ABC, Generic[S]):
    """
    Base class for all third-party automations.

    Developers extend this class to create custom automations.
    The SDK handles:
    - State initialization
    - Credential injection
    - Progress reporting
    - Error handling
    - Output collection

    Example:
        class MyAutomation(Automation[MyState]):
            def metadata(self) -> AutomationMetadata:
                return AutomationMetadata(
                    name="my-automation",
                    title="My Automation",
                    version="1.0.0",
                    description="Does something useful",
                )

            def get_state_class(self) -> type[MyState]:
                return MyState

            def build_graph(self) -> StateGraph:
                graph = StateGraph(MyState)
                graph.add_node("process", self.process)
                graph.set_entry_point("process")
                return graph

            def process(self, state: MyState) -> dict:
                # Process logic here
                return {
                    "output_data": {
                        "_version": 1,
                        "_blocks": [
                            {
                                "type": "text",
                                "label": "Result",
                                "content": "done",
                                "format": "plain",
                            }
                        ],
                    }
                }
    """

    @abstractmethod
    def metadata(self) -> AutomationMetadata:
        """
        Return automation metadata for marketplace listing.

        This metadata is used to display the automation in the marketplace
        and to validate the automation during submission.

        Returns:
            AutomationMetadata with name, description, version, etc.
        """
        pass

    @abstractmethod
    def get_state_class(self) -> type[S]:
        """
        Return the state TypedDict class for this automation.

        The state class must extend BaseState and define any additional
        fields needed by the automation.

        Returns:
            TypedDict subclass extending BaseState
        """
        pass

    @abstractmethod
    def build_graph(self) -> StateGraph:
        """
        Build and return the LangGraph workflow.

        This method should construct the StateGraph with all nodes,
        edges, and conditional logic. The graph should NOT be compiled;
        the runtime handles compilation.

        Returns:
            Configured StateGraph (not compiled)
        """
        pass

    def validate_input(self, input_data: dict[str, Any]) -> bool:
        """
        Optional input validation beyond JSON schema.

        Override this method to add custom validation logic that
        goes beyond what can be expressed in JSON schema.

        Args:
            input_data: User-provided input

        Returns:
            True if valid

        Raises:
            ValidationError: If input is invalid
        """
        return True

    def get_required_credentials(self) -> list[str]:
        """
        List of credential services required for this automation.

        These credentials MUST be configured by the user before
        the automation can execute.

        Returns:
            List of service names (e.g., ["google", "slack"])
        """
        return []

    def get_optional_credentials(self) -> list[str]:
        """
        List of optional credential services.

        These credentials may enhance functionality but are not
        required for the automation to run.

        Returns:
            List of service names
        """
        return []

    def on_startup(self) -> None:
        """
        Hook called before automation execution begins.

        Override to perform any initialization logic.
        """
        pass

    def on_shutdown(self) -> None:
        """
        Hook called after automation execution completes.

        Override to perform any cleanup logic.
        """
        pass

    def on_error(self, error: Exception) -> None:
        """
        Hook called when an error occurs during execution.

        Override to handle errors (e.g., logging, cleanup).

        Args:
            error: The exception that occurred
        """
        pass

    async def on_startup_async(self) -> None:
        """
        Async initialization hook called before automation execution begins.

        Override this for async setup operations like:
        - Async database connections
        - Async HTTP client initialization
        - Async cache warming
        - Any other async initialization logic

        This hook is called before on_startup() if both are overridden.
        """
        pass

    async def on_shutdown_async(self) -> None:
        """
        Async cleanup hook called after automation execution completes.

        Override this for async cleanup operations like:
        - Closing async connections
        - Flushing async buffers
        - Async resource cleanup
        - Any other async teardown logic

        This hook is called after on_shutdown() if both are overridden.
        """
        pass
