# /opt/docker/dev/service_finder/backend/app/services/logbook_service.py
"""
Logbook Service - GPS, OBDII és előfizetési szűrő kezelése.
"""
import logging
from typing import Optional, Tuple, Any
from decimal import Decimal
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.models import VehicleLogbook
from app.models import UserStats
from app.models.identity import User
from app.models.system import SystemParameter

logger = logging.getLogger("Logbook-Service-2.0")

class LogbookService:
    """
    Útnyilvántartás kezelése GPS koordinátákkal, OBDII adatokkal és előfizetési szintű jogosultságokkal.
    """

    @staticmethod
    async def get_system_parameter(db: AsyncSession, key: str, default: Any = None) -> Any:
        """
        Lekéri a rendszerparamétert a system.system_parameters táblából.
        Elsőként a global scope-ot keresi (scope_level='global', scope_id=NULL).
        Ha nem talál, visszaadja a default értéket.
        """
        stmt = select(SystemParameter).where(
            SystemParameter.key == key,
            SystemParameter.scope_level == 'global',
            SystemParameter.scope_id.is_(None),
            SystemParameter.is_active == True
        ).order_by(SystemParameter.updated_at.desc())
        result = await db.execute(stmt)
        param = result.scalar_one_or_none()
        if param and 'value' in param.value:
            return param.value['value']
        return default

    @staticmethod
    async def get_user_rank(db: AsyncSession, user_id: int) -> int:
        """
        Lekérdezi a felhasználó aktuális rankját (current_level) a UserStats táblából.
        Ha nincs rekord, alapértelmezett 0 (ingyenes szint).
        """
        stmt = select(UserStats.current_level).where(UserStats.user_id == user_id)
        result = await db.execute(stmt)
        rank = result.scalar_one_or_none()
        return rank if rank is not None else 0

    @staticmethod
    async def check_subscription_guard(
        db: AsyncSession,
        user_id: int,
        wants_gps: bool = False,
        wants_obd: bool = False
    ) -> Tuple[bool, str]:
        """
        Ellenőrzi, hogy a felhasználó előfizetési szintje engedélyezi-e a GPS/OBDII adatok rögzítését.
        
        Szabályok:
        - Rank >= LOGBOOK_GPS_MIN_RANK (alapértelmezett 50): engedélyezett a GPS távolság és koordináták
        - Rank >= 90 (VIP/Admin): minden engedélyezett (GPS, OBDII, gyorsulás)
        - Rank < LOGBOOK_GPS_MIN_RANK: csak manuális distance_km és trip_type rögzíthető
        
        Visszatérés: (allowed: bool, message: str)
        """
        rank = await LogbookService.get_user_rank(db, user_id)
        gps_min_rank = await LogbookService.get_system_parameter(db, 'LOGBOOK_GPS_MIN_RANK', 50)
        vip_min_rank = 90  # Fix VIP küszöb
        
        if rank >= vip_min_rank:
            return True, "VIP/Admin szint: minden adat rögzíthető"
        
        if rank >= gps_min_rank:
            if wants_gps or wants_obd:
                return True, f"PREMIUM szint (rank {rank} >= {gps_min_rank}): GPS és OBDII adatok rögzíthetők"
            return True, "PREMIUM szint"
        
        # Ingyenes felhasználó
        if wants_gps or wants_obd:
            return False, f"Ingyenes felhasználók (rank {rank} < {gps_min_rank}) nem rögzíthetnek GPS koordinátákat vagy OBDII adatokat. Csak manuális distance_km és trip_type engedélyezett."
        
        return True, "Ingyenes szint: csak manuális adatok"

    @staticmethod
    async def create_logbook_entry(
        db: AsyncSession,
        asset_id: str,
        driver_id: int,
        trip_type: str,
        start_mileage: int,
        end_mileage: Optional[int] = None,
        distance_km: Optional[float] = None,
        start_lat: Optional[float] = None,
        start_lng: Optional[float] = None,
        end_lat: Optional[float] = None,
        end_lng: Optional[float] = None,
        gps_calculated_distance: Optional[float] = None,
        obd_verified: bool = False,
        max_acceleration: Optional[float] = None,
        average_speed: Optional[float] = None,
    ) -> VehicleLogbook:
        """
        Új útnyilvántartás bejegyzés létrehozása előfizetési szűrővel.
        
        Automatikusan ellenőrzi, hogy a felhasználó rankja engedélyezi-e a GPS/OBDII mezők kitöltését.
        Ha nem, a GPS és OBDII mezők null-ra állnak, és csak a manuális distance_km marad.
        """
        # Ellenőrizzük a jogosultságot
        wants_gps = any([start_lat, start_lng, end_lat, end_lng, gps_calculated_distance])
        wants_obd = obd_verified or max_acceleration is not None or average_speed is not None
        
        allowed, message = await LogbookService.check_subscription_guard(
            db, driver_id, wants_gps, wants_obd
        )
        
        if not allowed:
            # Ha nem engedélyezett, nullázzuk a tiltott mezőket
            logger.warning(f"User {driver_id} attempted to log GPS/OBDII without permission. {message}")
            start_lat = start_lng = end_lat = end_lng = gps_calculated_distance = None
            obd_verified = False
            max_acceleration = average_speed = None
        
        # Új bejegyzés létrehozása
        new_entry = VehicleLogbook(
            asset_id=asset_id,
            driver_id=driver_id,
            trip_type=trip_type,
            start_mileage=start_mileage,
            end_mileage=end_mileage,
            distance_km=distance_km,
            start_lat=start_lat,
            start_lng=start_lng,
            end_lat=end_lat,
            end_lng=end_lng,
            gps_calculated_distance=gps_calculated_distance,
            obd_verified=obd_verified,
            max_acceleration=max_acceleration,
            average_speed=average_speed,
        )
        
        db.add(new_entry)
        await db.commit()
        await db.refresh(new_entry)
        
        logger.info(f"Logbook entry created for asset {asset_id}, driver {driver_id}, trip_type {trip_type}")
        return new_entry

    @staticmethod
    async def calculate_official_distance(
        start_coords: Tuple[float, float],
        end_coords: Tuple[float, float]
    ) -> Optional[float]:
        """
        TODO: OSRM/Google Maps API hívással számolja ki a legrövidebb útvonal távolságát.
        Egyelőre placeholder, később implementálandó.
        
        Visszatérés: távolság kilométerben (float) vagy None, ha nem sikerült.
        """
        # TODO: Integrálni OSRM vagy Google Maps Distance Matrix API-t
        # Példa: https://project-osrm.org/docs/v5.24.0/api/#route-service
        # Jelenleg egyszerű haversine formula alapján számolunk
        from math import radians, sin, cos, sqrt, atan2
        
        lat1, lon1 = start_coords
        lat2, lon2 = end_coords
        
        R = 6371.0  # Föld sugara km-ben
        
        lat1_rad = radians(lat1)
        lon1_rad = radians(lon1)
        lat2_rad = radians(lat2)
        lon2_rad = radians(lon2)
        
        dlon = lon2_rad - lon1_rad
        dlat = lat2_rad - lat1_rad
        
        a = sin(dlat / 2)**2 + cos(lat1_rad) * cos(lat2_rad) * sin(dlon / 2)**2
        c = 2 * atan2(sqrt(a), sqrt(1 - a))
        
        distance_km = R * c
        return round(distance_km, 2)