"""Application lifecycle management (TUI wrapper).

This module provides TUI-specific lifecycle management that wraps the core
lifecycle with additional features like hub connection and Styrene node
announcements.

Usage:
    from styrene.services.app_lifecycle import StyreneLifecycle
    from styrene.services.config import load_config

    # Initialize Styrene services
    config = load_config()
    lifecycle = StyreneLifecycle(config)

    # Start services
    lifecycle.initialize()

    # Use services...
    from styrened.services.rns_service import get_rns_service
    rns = get_rns_service()
    print(f"RNS initialized: {rns.is_initialized}")

    # Cleanup
    lifecycle.shutdown()
"""

import logging
from importlib.metadata import version as get_version
from typing import Any

from styrened.services.lifecycle import CoreLifecycle
from styrened.models.rns_error import RNSErrorState

from styrene.models.config import DeploymentMode, StyreneConfig
from styrene.services.config import get_default_config
from styrened.services.hub_connection import STYRENE_HUB_ADDRESS, get_hub_connection
from styrene.services.reticulum import get_operator_identity_object
from styrened.services.rns_service import get_rns_service

logger = logging.getLogger(__name__)


class StyreneLifecycle:
    """Manages Styrene TUI application lifecycle.

    This class wraps CoreLifecycle and adds TUI-specific features:
    - Hub connection
    - Styrene node announcements with version info
    - TUI-specific configuration handling

    Core functionality (RNS/LXMF initialization, shutdown) is delegated
    to CoreLifecycle from styrene-core.
    """

    def __init__(self, config: StyreneConfig | None = None) -> None:
        """Initialize lifecycle manager.

        Args:
            config: Application configuration. If None, uses default config.
        """
        self.config = config or get_default_config()
        self._core = CoreLifecycle(self.config.core)
        self._initialized = False

    @property
    def rns_error_state(self) -> RNSErrorState:
        """Get the RNS initialization error state.

        Returns:
            RNSErrorState with category and recovery guidance.
            If initialized successfully, returns NONE category.
        """
        return self._core.rns_error_state

    @property
    def is_initialized(self) -> bool:
        """Check if services are initialized.

        Returns:
            True if initialized, False otherwise.
        """
        return self._initialized

    def initialize(self) -> bool:
        """Initialize all Styrene services.

        Returns:
            True if initialization succeeded, False otherwise.
        """
        if self._initialized:
            logger.warning("Already initialized")
            return True

        try:
            # Initialize core services (RNS, LXMF)
            if not self._core.initialize():
                logger.warning("Core initialization failed - running in offline mode")
                # Don't fail entirely - allow offline mode
                self._initialized = True
                return True

            # Announce as Styrene node (TUI-specific)
            self._announce_styrene_node()

            # Connect to hub if configured (but not if we ARE the hub)
            if self.config.reticulum.hub_enabled:
                if self.config.reticulum.mode == DeploymentMode.HUB:
                    logger.info("Running in hub mode - skipping hub connection (we are the hub)")
                else:
                    self._connect_to_hub()

            self._initialized = True
            logger.info("Styrene TUI services initialized successfully")
            return True

        except Exception as e:
            logger.error(f"Initialization failed: {e}")
            return False

    def _announce_styrene_node(self) -> None:
        """Announce this node as a Styrene node (TUI-specific).

        Sends announce with Styrene node format including version and capabilities.
        """
        try:
            import socket

            # Get operator destination
            identity = get_operator_identity_object()
            if not identity:
                logger.warning("No operator identity for announce")
                return

            rns_service = get_rns_service()
            destination = rns_service.get_or_create_destination(
                identity, app_name="styrene_node", aspect="operator"
            )

            if not destination:
                logger.warning("Failed to get destination for announce")
                return

            # Build announce data: styrene:<hostname>:<version>:<capabilities>:<lxmf_dest>
            hostname = socket.gethostname()
            try:
                version = get_version("styrene-tui")
            except Exception:
                version = "unknown"

            # Capabilities
            capabilities = []
            if self.config.rpc.enabled:
                capabilities.append("rpc")
            if self.config.discovery.enabled:
                capabilities.append("discovery")
            capabilities_str = ",".join(capabilities) if capabilities else "none"

            # LXMF destination (if available)
            lxmf_dest = "none"
            try:
                from styrened.services.lxmf_service import get_lxmf_service

                lxmf_service = get_lxmf_service()
                if lxmf_service.is_initialized and lxmf_service.delivery_destination:
                    lxmf_dest = lxmf_service.delivery_destination.hash.hex()
            except Exception:
                pass

            # Format: styrene:<hostname>:<version>:<capabilities>:<lxmf_dest>
            announce_data = f"styrene:{hostname}:{version}:{capabilities_str}:{lxmf_dest}"

            # Send announce
            destination.announce(announce_data.encode("utf-8"))
            logger.info(f"Announced as Styrene node: {hostname} (v{version})")

        except Exception as e:
            logger.warning(f"Failed to announce Styrene node: {e}")

    def _connect_to_hub(self) -> bool:
        """Connect to Styrene hub for fleet coordination (TUI-specific).

        Returns:
            True if connected successfully, False otherwise.
        """
        try:
            hub_connection = get_hub_connection()

            # Determine hub address
            hub_address = self.config.reticulum.hub_address or STYRENE_HUB_ADDRESS

            if not hub_address:
                logger.warning("Hub enabled but no address configured")
                return False

            logger.info(f"Connecting to hub at {hub_address[:16]}...")

            if hub_connection.connect(hub_address=hub_address):
                logger.info(f"Connected to hub at {hub_address[:16]}...")
                return True
            else:
                logger.warning("Hub connection failed")
                return False

        except Exception as e:
            logger.error(f"Hub connection error: {e}")
            return False

    def shutdown(self) -> None:
        """Shutdown all services and clean up resources."""
        if not self._initialized:
            logger.debug("Not initialized, nothing to shutdown")
            return

        try:
            logger.info("Shutting down Styrene TUI services...")

            # Disconnect from hub (TUI-specific)
            get_hub_connection().disconnect()

            # Shutdown core services (RNS, LXMF, discovery)
            self._core.shutdown()

            self._initialized = False
            logger.info("Styrene TUI services shutdown complete")

        except Exception as e:
            logger.error(f"Error during shutdown: {e}")


def get_status() -> dict[str, Any]:
    """Get current status of all Styrene services.

    Returns:
        Dictionary with status information for all services.
    """
    from styrene.services.reticulum import get_reticulum_status

    hub_connection = get_hub_connection()
    reticulum_status = get_reticulum_status()

    return {
        "rns_initialized": reticulum_status.get("running", False),
        "hub_connected": hub_connection.is_connected,
        "hub_address": hub_connection.hub_address,
        "operator_identity": reticulum_status.get("identity"),
        "transport_enabled": reticulum_status.get("transport_enabled"),
        "interface_count": reticulum_status.get("interfaces"),
    }


# Backward compatibility aliases
get_service_status = get_status


def initialize_styrene(config: StyreneConfig | None = None) -> StyreneLifecycle:
    """Initialize Styrene services (backward compatibility wrapper).

    Args:
        config: Application configuration. If None, uses default config.

    Returns:
        Initialized StyreneLifecycle instance.
    """
    lifecycle = StyreneLifecycle(config)
    lifecycle.initialize()
    return lifecycle
