"""
Configuration Service
System settings and map provider configuration management
"""
from typing import Optional, List, Dict, Any
import logging

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

from app.models.system_config import SystemConfig, MapProviderConfig, MapProviderType, ConfigCategory
from app.services.map_provider import MapProviderFactory

logger = logging.getLogger(__name__)


class ConfigService:
    """System configuration management service"""
    
    @classmethod
    async def get_config(cls, db: AsyncSession, key: str) -> Optional[SystemConfig]:
        """Get a single configuration value"""
        query = select(SystemConfig).where(SystemConfig.key == key)
        result = await db.execute(query)
        return result.scalar_one_or_none()
    
    @classmethod
    async def get_config_value(cls, db: AsyncSession, key: str, default: Any = None) -> Any:
        """Get typed configuration value"""
        config = await cls.get_config(db, key)
        if config:
            return config.get_typed_value()
        return default
    
    @classmethod
    async def get_configs_by_category(
        cls,
        db: AsyncSession,
        category: ConfigCategory
    ) -> List[SystemConfig]:
        """Get all configurations in a category"""
        query = select(SystemConfig).where(
            SystemConfig.category == category,
            SystemConfig.is_visible == True
        ).order_by(SystemConfig.key)
        result = await db.execute(query)
        return list(result.scalars().all())
    
    @classmethod
    async def set_config(
        cls,
        db: AsyncSession,
        key: str,
        value: str
    ) -> SystemConfig:
        """Set a configuration value"""
        config = await cls.get_config(db, key)
        
        if not config:
            raise ValueError(f"Configuration key '{key}' not found")
        
        if not config.is_editable:
            raise ValueError(f"Configuration '{key}' is not editable")
        
        config.value = value
        await db.commit()
        await db.refresh(config)
        
        return config
    
    @classmethod
    async def set_configs_bulk(
        cls,
        db: AsyncSession,
        configs: Dict[str, str]
    ) -> List[SystemConfig]:
        """Set multiple configuration values"""
        updated = []
        for key, value in configs.items():
            try:
                config = await cls.set_config(db, key, value)
                updated.append(config)
            except ValueError as e:
                logger.warning(f"Failed to update config {key}: {e}")
        
        return updated
    
    # Map Provider Configuration
    
    @classmethod
    async def get_map_providers(cls, db: AsyncSession) -> List[MapProviderConfig]:
        """Get all map provider configurations"""
        query = select(MapProviderConfig).order_by(MapProviderConfig.priority.desc())
        result = await db.execute(query)
        return list(result.scalars().all())
    
    @classmethod
    async def get_active_map_provider(cls, db: AsyncSession) -> Optional[MapProviderConfig]:
        """Get the currently active map provider"""
        query = select(MapProviderConfig).where(
            MapProviderConfig.is_active == True,
            MapProviderConfig.is_configured == True
        ).order_by(MapProviderConfig.priority.desc())
        result = await db.execute(query)
        return result.scalar_one_or_none()
    
    @classmethod
    async def update_map_provider(
        cls,
        db: AsyncSession,
        provider_name: MapProviderType,
        api_key: Optional[str] = None,
        api_secret: Optional[str] = None,
        api_url: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        is_active: Optional[bool] = None,
        priority: Optional[int] = None
    ) -> MapProviderConfig:
        """Update map provider configuration"""
        query = select(MapProviderConfig).where(
            MapProviderConfig.provider_name == provider_name
        )
        result = await db.execute(query)
        config = result.scalar_one_or_none()
        
        if not config:
            # Create new configuration
            config = MapProviderConfig(
                provider_name=provider_name,
                display_name=provider_name.value.replace("_", " ").title(),
            )
            db.add(config)
        
        # Update fields
        if api_key is not None:
            config.api_key = api_key
            config.is_configured = bool(api_key)
        if api_secret is not None:
            config.api_secret = api_secret
        if api_url is not None:
            config.api_url = api_url
        if settings is not None:
            config.settings = settings
        if priority is not None:
            config.priority = priority
        
        # Handle activation
        if is_active is not None:
            if is_active:
                # Deactivate other providers first
                deactivate_query = select(MapProviderConfig).where(
                    MapProviderConfig.provider_name != provider_name,
                    MapProviderConfig.is_active == True
                )
                deactivate_result = await db.execute(deactivate_query)
                for other in deactivate_result.scalars():
                    other.is_active = False
            
            config.is_active = is_active
        
        await db.commit()
        await db.refresh(config)
        
        # Clear provider cache
        MapProviderFactory.clear_cache()
        
        return config
    
    @classmethod
    async def activate_map_provider(
        cls,
        db: AsyncSession,
        provider_name: MapProviderType
    ) -> MapProviderConfig:
        """Activate a specific map provider"""
        return await cls.update_map_provider(db, provider_name, is_active=True)
    
    @classmethod
    async def test_map_provider(
        cls,
        db: AsyncSession,
        provider_name: MapProviderType,
        test_address: str = "New York, NY"
    ) -> Dict[str, Any]:
        """Test a map provider configuration"""
        import time
        
        query = select(MapProviderConfig).where(
            MapProviderConfig.provider_name == provider_name
        )
        result = await db.execute(query)
        config = result.scalar_one_or_none()
        
        if not config or not config.api_key:
            return {
                "success": False,
                "error": "Provider not configured or missing API key"
            }
        
        # Create provider instance
        try:
            provider = MapProviderFactory.create_provider(
                provider_name,
                config.api_key,
                config.api_url,
                config.settings
            )
            
            # Time the test
            start = time.time()
            success, error = await provider.test_connection()
            elapsed_ms = int((time.time() - start) * 1000)
            
            # Update test results
            from datetime import datetime
            config.last_tested_at = datetime.utcnow()
            config.last_test_status = "success" if success else "failed"
            await db.commit()
            
            return {
                "success": success,
                "response_time_ms": elapsed_ms,
                "error": error
            }
        except Exception as e:
            return {
                "success": False,
                "error": str(e)
            }
    
    # Admin Dashboard Stats
    
    @classmethod
    async def get_dashboard_stats(cls, db: AsyncSession) -> Dict[str, Any]:
        """Get admin dashboard statistics"""
        from sqlalchemy import func
        from app.models.user import User, UserRole
        from app.models.driver import Driver, DriverStatus
        from app.models.ride import Ride, RideStatus
        from app.models.payment import Transaction
        from datetime import datetime, timedelta
        
        now = datetime.utcnow()
        today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)
        week_start = today_start - timedelta(days=7)
        month_start = today_start.replace(day=1)
        
        # User counts
        user_query = select(func.count()).select_from(User)
        passenger_query = select(func.count()).select_from(User).where(User.role == UserRole.PASSENGER)
        driver_query = select(func.count()).select_from(User).where(User.role == UserRole.DRIVER)
        
        total_users = (await db.execute(user_query)).scalar() or 0
        total_passengers = (await db.execute(passenger_query)).scalar() or 0
        total_drivers = (await db.execute(driver_query)).scalar() or 0
        
        # Active drivers
        active_drivers_query = select(func.count()).select_from(Driver).where(
            Driver.is_online == True,
            Driver.status == DriverStatus.APPROVED
        )
        active_drivers = (await db.execute(active_drivers_query)).scalar() or 0
        
        # Pending verifications
        pending_query = select(func.count()).select_from(Driver).where(
            Driver.status == DriverStatus.PENDING
        )
        pending_verifications = (await db.execute(pending_query)).scalar() or 0
        
        # Ride stats
        rides_query = select(func.count()).select_from(Ride)
        completed_query = select(func.count()).select_from(Ride).where(Ride.status == RideStatus.COMPLETED)
        active_query = select(func.count()).select_from(Ride).where(
            Ride.status.in_([RideStatus.REQUESTED, RideStatus.ACCEPTED, RideStatus.STARTED])
        )
        cancelled_query = select(func.count()).select_from(Ride).where(Ride.status == RideStatus.CANCELLED)
        
        total_rides = (await db.execute(rides_query)).scalar() or 0
        completed_rides = (await db.execute(completed_query)).scalar() or 0
        active_rides = (await db.execute(active_query)).scalar() or 0
        cancelled_rides = (await db.execute(cancelled_query)).scalar() or 0
        
        return {
            "total_users": total_users,
            "total_passengers": total_passengers,
            "total_drivers": total_drivers,
            "active_drivers": active_drivers,
            "pending_driver_verifications": pending_verifications,
            "total_rides": total_rides,
            "completed_rides": completed_rides,
            "active_rides": active_rides,
            "cancelled_rides": cancelled_rides,
            "total_revenue": 0,  # TODO: Calculate from transactions
            "total_commission": 0,
            "today_revenue": 0,
            "this_week_revenue": 0,
            "this_month_revenue": 0,
            "new_users_today": 0,
            "new_users_this_week": 0,
            "rides_today": 0,
            "rides_this_week": 0,
        }
