"""
Core LaneSwap client functionality.

This module provides the main LaneSwap class for integrating
Python services with LaneSwap Monitor.
"""

import signal
import sys
from typing import Any, Callable, List, Optional, Union

from .health import AsyncHealthCheckFunc, HealthCheckFunc, HealthCheckRegistry
from .utils import get_logger, get_port, get_service_name, setup_logging


class LaneSwap:
    """
    Main integration class for LaneSwap Monitor.

    This class handles signal registration, health checks, and shutdown
    management for Python services monitored by LaneSwap.

    Args:
        app: Optional Flask/FastAPI application instance
        service_name: Override SERVICE_NAME environment variable
        port: Override PORT environment variable
        setup_signals: Automatically register signal handlers (default: True)
        setup_logs: Automatically configure logging (default: True)

    Examples:
        Flask integration:
        >>> from flask import Flask
        >>> from laneswap import LaneSwap
        >>> app = Flask(__name__)
        >>> laneswap = LaneSwap(app)

        FastAPI integration:
        >>> from fastapi import FastAPI
        >>> from laneswap import LaneSwap
        >>> app = FastAPI()
        >>> laneswap = LaneSwap(app)

        Vanilla (no framework):
        >>> from laneswap import LaneSwap
        >>> laneswap = LaneSwap()
    """

    def __init__(
        self,
        app: Optional[Any] = None,
        service_name: Optional[str] = None,
        port: Optional[int] = None,
        setup_signals: bool = True,
        setup_logs: bool = True,
    ) -> None:
        """Initialize LaneSwap integration."""
        # Configuration
        self._service_name = get_service_name(service_name)
        self._port = get_port(port)
        self._app = app
        self._running = True

        # Registries
        self._health_registry = HealthCheckRegistry()
        self._shutdown_handlers: List[Callable[[], None]] = []

        # Logging
        if setup_logs:
            self._logger = setup_logging()
        else:
            self._logger = get_logger()

        # Signal handlers
        if setup_signals:
            self._register_signals()

        # Framework integration
        if app is not None:
            self._integrate_framework(app)

    def _register_signals(self) -> None:
        """Register SIGTERM and SIGINT handlers for graceful shutdown."""

        def signal_handler(signum: int, frame: Any) -> None:
            """Handle shutdown signals."""
            self._logger.info(f"Received signal {signum}, shutting down gracefully...")
            self._running = False
            self._execute_shutdown_handlers()
            self._logger.info("Shutdown complete")
            sys.exit(0)

        signal.signal(signal.SIGTERM, signal_handler)
        signal.signal(signal.SIGINT, signal_handler)

    def _integrate_framework(self, app: Any) -> None:
        """
        Auto-detect and integrate with web framework.

        Args:
            app: Flask, FastAPI, or other framework application instance
        """
        app_type = type(app).__name__

        if "Flask" in app_type:
            self._integrate_flask(app)
        elif "FastAPI" in app_type or "Starlette" in app_type:
            self._integrate_fastapi(app)
        else:
            # Unknown framework - user must manually add health endpoint
            self._logger.warning(
                f"Unknown framework type: {app_type}. "
                "You may need to manually register the /health endpoint."
            )

    def _integrate_flask(self, app: Any) -> None:
        """
        Integrate with Flask application.

        Args:
            app: Flask application instance
        """
        from .integrations.flask import setup_flask_integration

        setup_flask_integration(app, self)
        self._logger.info("Flask integration configured")

    def _integrate_fastapi(self, app: Any) -> None:
        """
        Integrate with FastAPI application.

        Args:
            app: FastAPI application instance
        """
        from .integrations.fastapi import setup_fastapi_integration

        setup_fastapi_integration(app, self)
        self._logger.info("FastAPI integration configured")

    def _execute_shutdown_handlers(self) -> None:
        """Execute all registered shutdown handlers (sync and async)."""
        import asyncio
        import inspect

        for handler in self._shutdown_handlers:
            try:
                if inspect.iscoroutinefunction(handler):
                    # Handler is async - run it in event loop
                    try:
                        loop = asyncio.get_event_loop()
                        if loop.is_running():
                            # If loop is running, create a new task
                            loop.create_task(handler())
                        else:
                            # Run in the loop
                            loop.run_until_complete(handler())
                    except RuntimeError:
                        # No event loop - create one
                        asyncio.run(handler())
                else:
                    # Handler is sync
                    handler()
            except Exception as e:
                self._logger.error(f"Error in shutdown handler: {e}")

    def health_check(
        self, func: Union[HealthCheckFunc, AsyncHealthCheckFunc]
    ) -> Union[HealthCheckFunc, AsyncHealthCheckFunc]:
        """
        Decorator to register a custom health check function.

        The function should return a dictionary that will be merged
        into the health check response, or None.

        Args:
            func: Health check function (sync or async)

        Returns:
            Original function (unchanged)

        Examples:
            Synchronous health check:
            >>> @laneswap.health_check
            ... def check_database():
            ...     db.ping()
            ...     return {"database": "connected"}

            Asynchronous health check:
            >>> @laneswap.health_check
            ... async def check_redis():
            ...     await redis.ping()
            ...     return {"redis": "connected"}
        """
        self._health_registry.register(func)
        return func

    def on_shutdown(self, func: Callable[[], None]) -> Callable[[], None]:
        """
        Decorator to register a shutdown handler.

        Shutdown handlers are called when SIGTERM/SIGINT is received,
        allowing cleanup of resources (close databases, stop workers, etc.).

        Args:
            func: Shutdown handler function

        Returns:
            Original function (unchanged)

        Examples:
            >>> @laneswap.on_shutdown
            ... def cleanup():
            ...     db.close()
            ...     logger.info("Database closed")

            >>> @laneswap.on_shutdown
            ... def stop_worker():
            ...     worker.stop()
        """
        self._shutdown_handlers.append(func)
        return func

    @property
    def running(self) -> bool:
        """
        Check if service should continue running.

        Returns:
            True if running, False if shutdown signal received

        Examples:
            >>> while laneswap.running:
            ...     # Main service loop
            ...     do_work()
        """
        return self._running

    @property
    def service_name(self) -> str:
        """
        Get service name from environment or override.

        Returns:
            Service name string
        """
        return self._service_name

    @property
    def port(self) -> int:
        """
        Get port number from environment or override.

        Returns:
            Port number
        """
        return self._port

    @property
    def health_registry(self) -> HealthCheckRegistry:
        """
        Get the health check registry.

        Returns:
            HealthCheckRegistry instance
        """
        return self._health_registry

    def run(self, main_func: Optional[Callable[[], None]] = None) -> None:
        """
        Run service with built-in HTTP server (vanilla mode).

        This starts a simple HTTP server for the /health endpoint
        and optionally runs a main function in the foreground.

        Args:
            main_func: Optional main function to run

        Examples:
            With main loop:
            >>> def main_loop():
            ...     while laneswap.running:
            ...         do_work()
            >>> laneswap.run(main_loop)

            Just HTTP server:
            >>> laneswap.run()  # Blocks until signal received
        """
        from .server import start_health_server

        # Start health check server in background
        server_thread = start_health_server(self)
        self._logger.info(f"Health server started on port {self._port}")

        try:
            if main_func is not None:
                # Run main function
                main_func()
            else:
                # Just keep server running
                while self._running:
                    import time

                    time.sleep(1)
        except KeyboardInterrupt:
            self._logger.info("Received keyboard interrupt")
        finally:
            self._running = False
            self._execute_shutdown_handlers()
            if server_thread:
                server_thread.join(timeout=5)

    def start_server(self) -> Any:
        """
        Start built-in HTTP server in background (vanilla mode).

        Returns the server thread for manual management if needed.
        For most cases, use run() instead which handles the server lifecycle.

        Returns:
            Server thread

        Examples:
            >>> laneswap.start_server()
            >>> # Your application logic here
            >>> while laneswap.running:
            ...     do_work()
        """
        from .server import start_health_server

        server_thread = start_health_server(self)
        self._logger.info(f"Health server started on port {self._port}")
        return server_thread
