# /opt/docker/dev/service_finder/backend/app/services/search_service.py
import logging
from typing import List, Optional, Dict, Any
from uuid import UUID

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_
from geoalchemy2.functions import ST_Distance, ST_MakePoint, ST_DWithin

from app.models.marketplace.service import ServiceProfile, ExpertiseTag
from app.models.marketplace.organization import Organization
from app.models.identity import User
from app.services.config_service import config

logger = logging.getLogger("Search-Service-2.4-Agnostic")

class SearchService:
    """
    Sentinel Master Search Service 2.4.
    Csomag-agnosztikus rangsoroló motor. 
    Minden üzleti logika (súlyozás, prioritás, láthatóság) az adatbázisból jön.
    """

    @staticmethod
    async def find_nearby_services(
        db: AsyncSession, 
        lat: float, 
        lon: float, 
        current_user: User,
        expertise_key: str = None
    ):
        try:
            # 1. HIERARCHIKUS RANGSOROLÁSI SZABÁLYOK LEKÉRÉSE
            # A config_service automatikusan a legspecifikusabbat adja vissza:
            # 1. User-specifikus (Céges egyedi beállítás)
            # 2. Package-specifikus (pl. 'free', 'premium', 'ultra_gold')
            # 3. Global (Alapértelmezett)
            
            user_tier = current_user.tier_name
            
            if current_user.role in [UserRole.superadmin, UserRole.admin]:
                user_tier = "vip"
                
            ranking_rules = await config.get_setting(
                db, 
                "RANKING_RULES", 
                user_id=current_user.id, # Ez a belső config_service-ben kezeli a hierarchiát
                package_slug=user_tier,
                default={
                    "ad_weight": 5000, 
                    "partner_weight": 1000, 
                    "trust_weight": 10, 
                    "dist_penalty": 20,
                    "pref_weight": 0,
                    "can_use_prefs": False,
                    "search_radius_km": 30
                }
            )

            # 2. PREFERENCIÁK (Ha a szabályrendszer engedi)
            user_prefs = {"networks": [], "ids": []}
            if ranking_rules.get("can_use_prefs", False):
                user_prefs = await config.get_setting(
                    db, "USER_SEARCH_PREFERENCES",
                    scope_level="user", scope_id=str(current_user.id),
                    default={"networks": [], "ids": []}
                )

            # 3. TÉRBELI LEKÉRDEZÉS
            user_point = ST_MakePoint(lon, lat)
            radius_m = ranking_rules.get("search_radius_km", 30) * 1000

            distance_col = ST_Distance(ServiceProfile.location, user_point).label("distance_meters")

            stmt = (
                select(ServiceProfile, Organization, distance_col)
                .join(Organization, ServiceProfile.organization_id == Organization.id)
                .where(
                    and_(
                        ST_DWithin(ServiceProfile.location, user_point, radius_m),
                        ServiceProfile.is_active == True
                    )
                )
            )

            if expertise_key:
                stmt = stmt.join(ServiceProfile.expertises).join(ExpertiseTag).where(ExpertiseTag.key == expertise_key)

            result = await db.execute(stmt)
            rows = result.all()

            # 4. UNIVERZÁLIS PONTOZÁS (Súlyozott mátrix alapján)
            final_results = []
            r = ranking_rules # Rövidítés a számításhoz

            for s_prof, org, dist_m in rows:
                dist_km = dist_m / 1000.0
                score = 0
                
                # --- PONTOZÁSI LOGIKA (Nincsenek fix csomagnevek!) ---
                
                # A. Hirdetési súly
                if s_prof.is_advertiser:
                    score += r.get("ad_weight", 0)

                # B. Partner (Minősített) súly
                if s_prof.is_verified_partner:
                    score += r.get("partner_weight", 0)

                # C. Minőség (Trust Score) súly
                score += (s_prof.trust_score * r.get("trust_weight", 0))

                # D. Egyéni/Céges preferencia súly (Csak ha engedélyezett)
                if r.get("can_use_prefs"):
                    if s_prof.network_slug in user_prefs.get("networks", []):
                        score += r.get("pref_weight", 0)
                    if str(org.id) in user_prefs.get("ids", []):
                        score += r.get("pref_weight", 0) * 1.2

                # E. Távolság büntetés
                score -= (dist_km * r.get("dist_penalty", 0))

                final_results.append({
                    "id": org.id,
                    "name": org.full_name,
                    "trust_score": s_prof.trust_score,
                    "distance_km": round(dist_km, 2),
                    "rank_score": round(score, 2),
                    "flags": {
                        "is_ad": s_prof.is_advertiser,
                        "is_partner": s_prof.is_verified_partner,
                        "is_favorite": str(org.id) in user_prefs.get("ids", [])
                    }
                })

            # 5. RENDEZÉS
            return sorted(final_results, key=lambda x: x['rank_score'], reverse=True)

        except Exception as e:
            logger.error(f"Search Service 2.4 Critical Error: {e}")
            raise e