# /opt/docker/dev/service_finder/backend/app/services/ai_service.py
import os
import json
import logging
import asyncio
import httpx
from typing import Dict, Any, Optional, List
from sqlalchemy import select

from app.db.session import AsyncSessionLocal 
from app.models.system import SystemParameter
from app.services.config_service import config

logger = logging.getLogger("AI-Service-2.2-Gateway")

class AIService:
    """
    Sentinel Master AI Service 2.2 - Multi-Agent & Fallback Gateway.
    Felelős az LLM hívásokért. Ha a helyi GPU (Ollama) túlterhelt, 
    automatikusan áttér a felhős (Groq/Gemini) megoldásokra.
    """

    @classmethod
    async def _execute_ai_call(cls, db, prompt: str, model_key: str = "text", images: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
        """
        Központi AI végrehajtó intelligens teherelosztással (Load Balancing).
        """
        # 1. BEÁLLÍTÁSOK LEKÉRÉSE
        base_url = await config.get_setting(db, "ai_ollama_url", default="http://ollama:11434/api/generate")
        delay = await config.get_setting(db, "AI_REQUEST_DELAY", default=0.1)
        temp = await config.get_setting(db, "ai_temperature", default=0.1)
        
        # A helyi timeout-ot levesszük 25 mp-re. Ha az RTX 3090 eddig nem végez, 
        # akkor biztosan tele van a várólistája, és azonnal átváltunk felhőbe.
        local_timeout = await config.get_setting(db, "ai_timeout_local", default=25.0) 

        # Fallback engedélyezése a konfigurációból
        enable_fallback_setting = await config.get_setting(db, "ENABLE_AI_FALLBACK", default="false")
        enable_fallback = str(enable_fallback_setting).lower() == "true"

        # Helyi modellek definiálása
        default_model = "llama3.2-vision:latest" if model_key == "vision" else "qwen2.5-coder:14b"
        model_name = await config.get_setting(db, f"ai_model_{model_key}", default=default_model)

        await asyncio.sleep(float(delay))

        # 2. ELSŐDLEGES PRÓBA: Helyi Ollama szerver (Ingyenes, VRAM alapú)
        try:
            payload = {
                "model": model_name,
                "prompt": prompt,
                "stream": False,
                "format": "json",
                "options": {"temperature": float(temp)}
            }
            if images:
                payload["images"] = images

            logger.info(f"🧠 Helyi AI ({model_name}) hívása indult...")
            async with httpx.AsyncClient(timeout=float(local_timeout)) as client:
                response = await client.post(base_url, json=payload)
                response.raise_for_status()
                
                raw_res = response.json().get("response", "{}")
                return json.loads(raw_res)

        except (httpx.ReadTimeout, httpx.ConnectError) as e:
            logger.warning(f"⚠️ Helyi GPU túlterhelt vagy lassú (Timeout/ConnectError). Váltás Fallback módba!")
        except json.JSONDecodeError as je:
            logger.error(f"❌ Helyi AI JSON parszolási hiba: {je}. Váltás Fallback módba!")
        except Exception as e:
            logger.error(f"❌ Helyi AI váratlan hiba: {e}. Váltás Fallback módba!")

        # 3. MÁSODLAGOS PRÓBA: Hibrid Fallback (Csak ha engedélyezve van és a helyi elbukott)
        if enable_fallback:
            return await cls._fallback_ai_call(prompt, model_key, images, float(temp))
        else:
            logger.error("❌ A Fallback ki van kapcsolva (.env), a feladat feldolgozása sikertelen.")
            return None

    @classmethod
    async def _fallback_ai_call(cls, prompt: str, model_key: str, images: Optional[List[str]], temp: float) -> Optional[Dict[str, Any]]:
        """ Külső API hívások (Groq és Gemini) vészhelyzet esetére. """
        
        if model_key == "vision" and images:
            # ---------------------------------------------------------
            # VISION FALLBACK: GOOGLE GEMINI 1.5 FLASH (Képelemzés/OCR)
            # ---------------------------------------------------------
            gemini_api_key = os.getenv("GEMINI_API_KEY")
            if not gemini_api_key:
                logger.error("❌ Hiányzik a GEMINI_API_KEY! Képtelen Fallback módban OCR-t végezni.")
                return None
                
            logger.info("☁️ Google Gemini 1.5 API (Vision) hívása...")
            url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key={gemini_api_key}"
            
            payload = {
                "contents": [{
                    "parts": [
                        {"text": prompt + "\nKérlek, SZIGORÚAN csak érvényes JSON objektummal válaszolj, Markdown formázás (```json) nélkül!"},
                        {"inline_data": {
                            "mime_type": "image/jpeg", # A korábbi kódban JPEG-be konvertáljuk
                            "data": images[0]
                        }}
                    ]
                }],
                "generationConfig": {
                    "temperature": temp,
                    "response_mime_type": "application/json" # Gemini specifikus JSON kényszerítés
                }
            }
            
            try:
                async with httpx.AsyncClient(timeout=30.0) as client:
                    resp = await client.post(url, json=payload)
                    resp.raise_for_status()
                    data = resp.json()
                    text_res = data["candidates"][0]["content"]["parts"][0]["text"]
                    return json.loads(text_res)
            except Exception as e:
                logger.error(f"❌ Gemini Fallback kritikus hiba: {e}")
                return None

        else:
            # ---------------------------------------------------------
            # TEXT FALLBACK: GROQ CLOUD (Szövegelemzés / Web Scraping)
            # ---------------------------------------------------------
            groq_api_key = os.getenv("GROQ_API_KEY")
            if not groq_api_key:
                logger.error("❌ Hiányzik a GROQ_API_KEY! Képtelen Fallback módban szöveget elemezni.")
                return None
            
            logger.info("☁️ Groq Cloud (Llama 3 8B) hívása...")
            url = "[https://api.groq.com/openai/v1/chat/completions](https://api.groq.com/openai/v1/chat/completions)"
            headers = {
                "Authorization": f"Bearer {groq_api_key}",
                "Content-Type": "application/json"
            }
            
            payload = {
                "model": "llama3-8b-8192", # Villámgyors szöveges modell
                "messages": [{"role": "user", "content": prompt}],
                "temperature": temp,
                "response_format": {"type": "json_object"} # Groq specifikus JSON kényszerítés
            }
            
            try:
                async with httpx.AsyncClient(timeout=20.0) as client:
                    resp = await client.post(url, headers=headers, json=payload)
                    resp.raise_for_status()
                    data = resp.json()
                    text_res = data["choices"][0]["message"]["content"]
                    return json.loads(text_res)
            except Exception as e:
                logger.error(f"❌ Groq Fallback kritikus hiba: {e}")
                return None

    # --- A TÖBBI METÓDUS VÁLTOZATLAN MARAD ---

    @classmethod
    async def get_gold_data_from_research(cls, make: str, model: str, raw_context: str) -> Optional[Dict[str, Any]]:
        async with AsyncSessionLocal() as db:
            template = await config.get_setting(db, "ai_prompt_gold_data", default="Extract technical car data for {make} {model} from: {context}")
            full_prompt = template.format(make=make, model=model, context=raw_context)
            return await cls._execute_ai_call(db, full_prompt, model_key="text")

    @classmethod
    async def get_clean_vehicle_data(cls, make: str, raw_model: str, sources: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        async with AsyncSessionLocal() as db:
            template = await config.get_setting(db, "ai_prompt_normalization", default="Normalize car model names: {make} {model}. Sources: {sources}")
            full_prompt = template.format(make=make, model=raw_model, sources=json.dumps(sources))
            return await cls._execute_ai_call(db, full_prompt, model_key="text")

    @classmethod
    async def process_ocr_document(cls, doc_type: str, base64_image: str) -> Optional[Dict[str, Any]]:
        async with AsyncSessionLocal() as db:
            template = await config.get_setting(db, f"ai_prompt_ocr_{doc_type}", default="Analyze this {doc_type} image and return structured JSON data.")
            full_prompt = template.format(doc_type=doc_type)
            # Itt mondjuk meg a diszpécsernek, hogy ez egy Vision feladat!
            return await cls._execute_ai_call(db, full_prompt, model_key="vision", images=[base64_image])