"""Decorators for easy vikdata service integration."""

import asyncio
import os
from collections.abc import Callable
from contextlib import asynccontextmanager
from typing import Any

from .client import VikdataClient
from .config import VikdataConfig
from .health import HealthChecker, HealthReporter
from .middleware import VikdataMiddleware
from .models import ServiceRegistration
from .usage import UsageReporter


def vikdata_service(
    name: str,
    service_url: str,
    vikdata_url: str | None = None,
    health_endpoint: str = "/health",
    description: str | None = None,
    permissions: list[str] | None = None,
    enable_usage_tracking: bool = True,
    enable_health_reporting: bool = True,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
    """Decorator for easy vikdata service integration.

    Automatically:
    - Registers service with vikdata on startup
    - Sets up JWT validation middleware
    - Configures usage tracking (optional)
    - Configures health reporting (optional)
    - Deregisters service on shutdown

    Args:
        name: Service name (e.g., "fishinfo")
        service_url: Base URL of this service
        vikdata_url: vikdata API URL (default: from VIKDATA_BASE_URL env)
        health_endpoint: Health check endpoint path
        description: Service description
        permissions: List of permissions this service provides
        enable_usage_tracking: Enable automatic usage tracking
        enable_health_reporting: Enable automatic health reporting

    Example:
        ```python
        from fastapi import FastAPI
        from vikdata import vikdata_service

        @vikdata_service(
            name="fishinfo",
            service_url="https://fishinfo.example.com",
            vikdata_url="https://api.vikdata.com",
        )
        def create_app() -> FastAPI:
            app = FastAPI()
            # ... add routes
            return app
        ```
    """

    def decorator(create_app_fn: Callable[..., Any]) -> Callable[..., Any]:
        def wrapper(*args: Any, **kwargs: Any) -> Any:
            # Initialize client
            config = VikdataConfig(base_url=vikdata_url or os.environ.get("VIKDATA_BASE_URL", ""))
            client = VikdataClient.from_config(config)

            # Create app
            app = create_app_fn(*args, **kwargs)

            # Storage for service registration
            registration: ServiceRegistration | None = None
            usage_reporter: UsageReporter | None = None
            health_reporter: HealthReporter | None = None

            # Define lifespan
            @asynccontextmanager
            async def lifespan(app: Any) -> Any:
                nonlocal registration, usage_reporter, health_reporter

                # Register service
                try:
                    registration = await client.services.register(
                        name=name,
                        service_url=service_url,
                        health_endpoint=health_endpoint,
                        description=description,
                        permissions=permissions,
                    )

                    # Update API key from registration
                    client.api_key = registration.api_key
                    client._http.headers["Authorization"] = f"Bearer {registration.api_key}"

                    # Start usage tracking
                    if enable_usage_tracking:
                        usage_reporter = UsageReporter(
                            client=client,
                            service=name,
                            batch_size=config.usage_batch_size,
                            flush_interval=config.usage_flush_interval,
                        )
                        await usage_reporter.start()

                    # Start health reporting
                    if enable_health_reporting:
                        health_checker = HealthChecker()
                        # Store health_checker on app for user access
                        app.state.health_checker = health_checker

                        health_reporter = HealthReporter(
                            health_checker=health_checker,
                            service_id=registration.id,
                            client=client,
                            interval=config.health_check_interval,
                        )
                        await health_reporter.start()

                except Exception as e:
                    print(f"Warning: Failed to register with vikdata: {e}")

                yield

                # Cleanup
                if usage_reporter:
                    await usage_reporter.stop()

                if health_reporter:
                    await health_reporter.stop()

                if registration:
                    try:
                        await client.services.unregister(registration.id)
                    except Exception as e:
                        print(f"Warning: Failed to unregister from vikdata: {e}")

                await client.close()

            # Attach lifespan to app
            if hasattr(app, "router") and hasattr(app.router, "lifespan_context"):
                # FastAPI app - wrap existing lifespan if present
                original_lifespan = app.router.lifespan_context

                @asynccontextmanager
                async def combined_lifespan(app: Any) -> Any:
                    async with lifespan(app):
                        if original_lifespan:
                            async with original_lifespan(app):
                                yield
                        else:
                            yield

                app.router.lifespan_context = combined_lifespan
            else:
                # Not a FastAPI app or no lifespan support
                print("Warning: App does not support lifespan, skipping automatic registration")

            # Add middleware
            if usage_reporter is not None:
                app.add_middleware(
                    VikdataMiddleware,
                    client=client,
                    usage_reporter=usage_reporter,
                )
            else:
                app.add_middleware(
                    VikdataMiddleware,
                    client=client,
                )

            # Store client on app for access
            app.state.vikdata_client = client

            return app

        return wrapper

    return decorator


class ServiceManager:
    """Manual service manager for more control over registration and lifecycle."""

    def __init__(
        self,
        name: str,
        service_url: str,
        client: VikdataClient,
        health_endpoint: str | None = None,
        description: str | None = None,
        permissions: list[str] | None = None,
    ) -> None:
        """Initialize service manager.

        Args:
            name: Service name
            service_url: Service base URL
            client: VikdataClient instance
            health_endpoint: Health check endpoint
            description: Service description
            permissions: Service permissions
        """
        self.name = name
        self.service_url = service_url
        self.client = client
        self.health_endpoint = health_endpoint
        self.description = description
        self.permissions = permissions

        self.registration: ServiceRegistration | None = None
        self.usage_reporter: UsageReporter | None = None
        self.health_checker: HealthChecker | None = None
        self.health_reporter: HealthReporter | None = None

    async def register(self) -> ServiceRegistration:
        """Register service with vikdata.

        Returns:
            ServiceRegistration with API key
        """
        self.registration = await self.client.services.register(
            name=self.name,
            service_url=self.service_url,
            health_endpoint=self.health_endpoint,
            description=self.description,
            permissions=self.permissions,
        )

        # Update client API key
        self.client.api_key = self.registration.api_key
        self.client._http.headers["Authorization"] = f"Bearer {self.registration.api_key}"

        return self.registration

    async def unregister(self) -> None:
        """Unregister service from vikdata."""
        if self.registration:
            await self.client.services.unregister(self.registration.id)
            self.registration = None

    def enable_usage_tracking(
        self,
        batch_size: int = 100,
        flush_interval: float = 60.0,
    ) -> UsageReporter:
        """Enable usage tracking.

        Args:
            batch_size: Batch size for reporting
            flush_interval: Flush interval in seconds

        Returns:
            UsageReporter instance
        """
        self.usage_reporter = UsageReporter(
            client=self.client,
            service=self.name,
            batch_size=batch_size,
            flush_interval=flush_interval,
        )
        return self.usage_reporter

    def enable_health_reporting(
        self,
        interval: float = 30.0,
    ) -> tuple[HealthChecker, HealthReporter]:
        """Enable health reporting.

        Args:
            interval: Report interval in seconds

        Returns:
            Tuple of (HealthChecker, HealthReporter)
        """
        if not self.registration:
            raise RuntimeError("Service must be registered before enabling health reporting")

        self.health_checker = HealthChecker()
        self.health_reporter = HealthReporter(
            health_checker=self.health_checker,
            service_id=self.registration.id,
            client=self.client,
            interval=interval,
        )

        return self.health_checker, self.health_reporter

    async def start(self) -> None:
        """Start background tasks."""
        if self.usage_reporter:
            await self.usage_reporter.start()

        if self.health_reporter:
            await self.health_reporter.start()

    async def stop(self) -> None:
        """Stop background tasks."""
        if self.usage_reporter:
            await self.usage_reporter.stop()

        if self.health_reporter:
            await self.health_reporter.stop()

    @asynccontextmanager
    async def lifespan(self) -> Any:
        """Context manager for FastAPI lifespan.

        Example:
            ```python
            manager = ServiceManager(...)

            @asynccontextmanager
            async def app_lifespan(app: FastAPI):
                async with manager.lifespan():
                    yield

            app = FastAPI(lifespan=app_lifespan)
            ```
        """
        await self.register()
        await self.start()

        try:
            yield
        finally:
            await self.stop()
            await self.unregister()
