"""
Map Provider Factory
Factory pattern for instantiating the active map provider based on database configuration
"""
from typing import Optional
import logging

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.models.system_config import MapProviderConfig, MapProviderType
from app.services.map_provider.base_provider import MapProvider
from app.services.map_provider.mapbox_provider import MapboxProvider
from app.services.map_provider.google_maps_provider import GoogleMapsProvider
from app.config import settings

logger = logging.getLogger(__name__)


class MapProviderFactory:
    """
    Factory class to create map provider instances based on configuration.
    Uses database settings to determine which provider is active.
    """
    
    # Provider class mapping
    PROVIDERS = {
        MapProviderType.MAPBOX: MapboxProvider,
        MapProviderType.GOOGLE_MAPS: GoogleMapsProvider,
        # Add more providers here
    }
    
    # Cached provider instance
    _cached_provider: Optional[MapProvider] = None
    _cached_provider_name: Optional[str] = None
    
    @classmethod
    async def get_provider(cls, db: AsyncSession) -> MapProvider:
        """
        Get the active map provider based on database configuration.
        Uses caching to avoid repeated database queries.
        
        Args:
            db: Database session
            
        Returns:
            MapProvider instance
        """
        # Query for active provider
        query = select(MapProviderConfig).where(
            MapProviderConfig.is_active == True,
            MapProviderConfig.is_configured == True
        ).order_by(MapProviderConfig.priority.desc())
        
        result = await db.execute(query)
        config = result.scalar_one_or_none()
        
        if config:
            # Check if we can use cached provider
            if (cls._cached_provider and 
                cls._cached_provider_name == config.provider_name.value):
                return cls._cached_provider
            
            # Create new provider instance
            provider_class = cls.PROVIDERS.get(config.provider_name)
            if provider_class:
                provider = provider_class(
                    api_key=config.api_key,
                    api_url=config.api_url,
                    settings=config.settings
                )
                cls._cached_provider = provider
                cls._cached_provider_name = config.provider_name.value
                logger.info(f"Using map provider: {config.provider_name.value}")
                return provider
        
        # Fallback to default provider from environment
        return cls.get_default_provider()
    
    @classmethod
    def get_default_provider(cls) -> MapProvider:
        """
        Get default map provider from environment settings.
        Used as fallback when no database configuration exists.
        """
        provider_name = settings.default_map_provider.lower()
        
        if provider_name == "google_maps":
            return GoogleMapsProvider(
                api_key=settings.google_maps_api_key,
                api_url=settings.google_maps_api_url
            )
        else:
            # Default to Mapbox
            return MapboxProvider(
                api_key=settings.mapbox_access_token,
                api_url=settings.mapbox_api_url
            )
    
    @classmethod
    def create_provider(
        cls,
        provider_type: MapProviderType,
        api_key: str,
        api_url: Optional[str] = None,
        settings: Optional[dict] = None
    ) -> MapProvider:
        """
        Create a specific provider instance.
        
        Args:
            provider_type: Type of provider to create
            api_key: API key for the provider
            api_url: Optional custom API URL
            settings: Optional provider-specific settings
            
        Returns:
            MapProvider instance
        """
        provider_class = cls.PROVIDERS.get(provider_type)
        if not provider_class:
            raise ValueError(f"Unknown provider type: {provider_type}")
        
        return provider_class(api_key=api_key, api_url=api_url, settings=settings)
    
    @classmethod
    def clear_cache(cls):
        """Clear cached provider instance"""
        cls._cached_provider = None
        cls._cached_provider_name = None
        logger.info("Map provider cache cleared")


from fastapi import Depends
from app.database import get_db

async def get_map_provider(db: AsyncSession = Depends(get_db)) -> MapProvider:
    """
    Dependency function to get map provider.
    
    Usage:
        @app.get("/example")
        async def example(
            db: AsyncSession = Depends(get_db),
            map_provider: MapProvider = Depends(get_map_provider)
        ):
            result = await map_provider.geocode("New York, NY")
    """
    return await MapProviderFactory.get_provider(db)
