"""
WhatsApp API Wrapper - wasup.py
~~~~~~~~~~~~~~~~~~~~~~
A stateful WhatsApp API Wrapper for Python with built-in conversation flow management,
supporting multiple providers.

:copyright: (c) 2025-present June
:license: MIT, see LICENSE for more details.
"""

__title__ = "whatsapp"
__author__ = "June"
__license__ = "MIT"
__copyright__ = "2025-present June"
__version__ = "0.3.0"

import asyncio
from typing import Callable, Dict, Union

from whatsapp.bindings import BaseBindingClient
from whatsapp.messages.dialogs import Dialog
from whatsapp.middleware.inactivity import InactivityManager
from whatsapp.middleware.storage import InMemoryStore, SessionStore

# optional imports for extras (bindings)
try:
    from whatsapp.bindings.azure import AzureBindingClient

    __all_azure__ = ["AzureBindingClient"]
except ImportError:
    __all_azure__ = []

try:
    from whatsapp.middleware.storage import RedisStore

    __all_redis__ = ["RedisStore"]
except ImportError:
    __all_redis__ = []

__all__ = (
    [
        # Core
        "Bot",
        # Bindings
        "BaseBindingClient",
        "ChatContext",
        # Messages
        "TextMessage",
        "InteractiveTextMessage",
        # Dialogs
        "Dialog",
        "DialogContext",
        "DialogTurnStatus",
        "DialogTurnResult",
        # Middleware
        "InactivityManager",
        "SessionStore",
        "InMemoryStore",
    ]
    + __all_azure__
    + __all_redis__
)


class Bot:
    """
    Main Bot class for managing WhatsApp conversations with dialog flows and middleware.

    Handles dialog registration, session management, and inactivity monitoring for WhatsApp-based chatbots.
    """

    def __init__(
        self,
        inactivity: Callable[[InMemoryStore], InMemoryStore] = None,
        session: Callable[[InactivityManager], InactivityManager] = None,
        port: int = 8000,
    ):
        """
        Initialize the WhatsApp Bot.

        Args:
            inactivity: Optional custom inactivity manager. Defaults to InactivityManager with 15-minute timeout.
            session: Optional custom session store. Defaults to InMemoryStore.
            port: Port number for the bot server. Defaults to 8000.
        """
        # load middleware
        self.session_store = session if session else InMemoryStore()
        self.inactivity_manager = (
            inactivity
            if inactivity
            else InactivityManager(
                prompt_message="Are you still there? Please respond to continue the session.",
                close_message="Session closed due to inactivity.",
                inactivity_minutes=15,
                confirmation_minutes=5,
            )
        )

        # initiate dialog context
        self.dialog_registry: Dict[str, Dialog] = {}

        # initialize port (for bindings that require it)
        self.port = port

        pass

    def load_dialog(self, dialog: Dialog):
        """
        Register a dialog and all its child dialogs recursively.

        Args:
            dialog: The Dialog instance to register. Child dialogs within the dialog's dialogs
                   dictionary will also be registered recursively.
        """
        if dialog.id in self.dialog_registry:
            return  # already registered

        self.dialog_registry[dialog.id] = dialog

        # Recursively register child dialogs
        if hasattr(dialog, "dialogs") and isinstance(dialog.dialogs, dict):
            for child_dialog in dialog.dialogs.values():
                self.load_dialog(child_dialog)

    def run(self, client: Union[BaseBindingClient, "AzureBindingClient"]):
        """
        Run the bot with the given binding client.

        The binding client handles incoming messages from the messaging platform,
        event processing, and routing logic to the bot. Supports both sync and async entry points.

        Args:
            client: An instance of a binding client (e.g., AzureBindingClient, BaseBindingClient).
                   Must implement a run() method.
        """
        # Support both sync and async entry points
        if hasattr(client, "run"):
            asyncio.run(client.run())

    def on_event(self):
        """
        Decorator for registering custom event handlers (not yet implemented).

        TODO: Implement event handler registration. Should support async functions
              for events like on_message, on_error, etc.
        """

        # TODO
        # pass from downstream binding
        # also! must be:
        # - async
        # - get function name (on_message, on_error, etc)
        def decorator(func):
            pass

        return decorator

    def _send_message(self):
        """
        Send a message to the user (internal use by middleware).

        TODO: Implement message sending. Should be called by middleware processes
              like InactivityManager to send system messages to users.
        """
        """
        Sends a message to the user. Only to be used by middleware processes.

        :param self: Description
        """
        pass
