# Copyright (c) 2025-2026 Dmitrii Gagarin aka madgagarin
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

from abc import ABC, abstractmethod
from collections.abc import AsyncIterator, Awaitable, Callable
from typing import Any

from ..models import (
    Heartbeat,
    TaskPayload,
    TaskResult,
    TokenResponse,
    WorkerCommand,
    WorkerEventPayload,
    WorkerRegistration,
)


class Transport(ABC):
    """
    Abstract Base Class for RXON Transports (Worker Side).
    Implementations of this class handle the physical communication
    between a Holon Shell (Worker) and its Ghost (Orchestrator).
    """

    @abstractmethod
    async def connect(self) -> None:
        """
        Establish connection or initialize transport.
        Configuration (endpoint, token, etc.) should be passed to the constructor.
        """
        pass

    @abstractmethod
    async def close(self) -> None:
        """
        Close transport resources.
        """
        pass

    @abstractmethod
    async def register(self, registration: WorkerRegistration) -> Any:
        """
        Register the holon shell with the orchestrator.
        Returns response data if successful.
        Raises RxonError subclass on failure.
        """
        pass

    @abstractmethod
    async def poll_task(self, timeout: float = 30.0) -> TaskPayload | None:
        """
        Long-poll for the next available task.
        Returns None if no task available (timeout/204).
        Raises RxonError subclass on failure.
        """
        pass

    @abstractmethod
    async def send_result(self, result: TaskResult, max_retries: int = 3, initial_delay: float = 0.1) -> bool:
        """
        Send task execution result back to orchestrator.
        Returns True if successful.
        Raises RxonError subclass on failure (after retries).
        """
        pass

    @abstractmethod
    async def send_heartbeat(self, heartbeat: Heartbeat) -> dict[str, Any] | None:
        """
        Update holon status and availability.
        Returns response data (e.g. commands) if successful.
        Raises RxonError subclass on failure.
        """
        pass

    @abstractmethod
    async def emit_event(self, event: WorkerEventPayload) -> bool:
        """
        Emit a generic worker event (Bottom-Up Initiative).
        """
        pass

    @abstractmethod
    def listen_for_commands(self) -> AsyncIterator[WorkerCommand]:
        """
        Listen for incoming commands from the orchestrator (e.g., via WebSocket).
        """
        pass

    @abstractmethod
    async def refresh_token(self) -> TokenResponse | None:
        """
        Refresh the authentication token (e.g. using STS).
        """
        pass


class Listener(ABC):
    """
    Abstract Base Class for RXON Listeners (Orchestrator Side).
    Implementations of this class listen for incoming worker connections
    and route them to the Orchestrator Engine.
    """

    @abstractmethod
    async def start(
        self,
        handler: Callable[[str, Any, dict[str, Any]], Awaitable[Any]],
    ) -> None:
        """
        Start the listener.
        The handler callback accepts (message_type, payload, context) and returns a response.
        Context usually contains authentication info (e.g., 'token', 'worker_id').
        """
        pass

    @abstractmethod
    async def stop(self) -> None:
        """
        Stop the listener and release ports/resources.
        """
        pass
