# /opt/docker/dev/service_finder/backend/app/services/geo_service.py
import uuid
import logging
from typing import Optional, List, Dict, Any
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import text, select

from app.services.config_service import config # 2.0 Dinamikus konfig
from app.db.session import AsyncSessionLocal

logger = logging.getLogger("Geo-Service-2.2")

class GeoService:
    """
    Sentinel Master GeoService 2.2.
    Felelős a címek normalizálásáért, a szótárak építéséért és a téradatokért.
    Minden paraméter (ország, sablon, limit) adminból vezérelt.
    """

    @staticmethod
    async def get_street_suggestions(db: AsyncSession, zip_code: str, q: str, user_id: Optional[int] = None) -> List[str]:
        """
        Autocomplete támogatás az utcákhoz.
        A limitet és a keresési logikát az adminból vesszük.
        """
        # 1. Admin beállítások lekérése
        search_limit = await config.get_setting(db, "GEO_SUGGESTION_LIMIT", default=10)
        
        query = text("""
            SELECT DISTINCT s.name 
            FROM data.geo_streets s
            JOIN data.geo_postal_codes p ON s.postal_code_id = p.id
            WHERE p.zip_code = :zip AND s.name ILIKE :q
            ORDER BY s.name ASC LIMIT :limit
        """)
        try:
            res = await db.execute(query, {"zip": zip_code, "q": f"{q}%", "limit": search_limit})
            return [row[0] for row in res.fetchall()]
        except Exception as e:
            logger.error(f"Street Suggestion Error: {e}")
            return []

    @staticmethod
    async def get_or_create_full_address(
        db: AsyncSession, 
        zip_code: str, 
        city: str, 
        street_name: str, 
        street_type: str, 
        house_number: str, 
        stairwell: Optional[str] = None, 
        floor: Optional[str] = None, 
        door: Optional[str] = None, 
        parcel_id: Optional[str] = None,
        user_id: Optional[int] = None # A régió-alapú felülbíráláshoz
    ) -> uuid.UUID:
        """
        Hibrid címrögzítés atomizált mezőkkel.
        A cím generálásának módja (sablonja) régió- vagy felhasználó-specifikus lehet.
        """
        try:
            # 1. ADMIN BEÁLLÍTÁSOK LEKÉRÉSE (Hierarchikus: User > Region > Global)
            # Országkód (pl. HU, AT, DE)
            default_country = await config.get_setting(
                db, "geo_default_country_code", 
                scope_level="user" if user_id else "global", 
                scope_id=str(user_id) if user_id else None,
                default="HU"
            )

            # Címformázási sablon (pl. "{zip} {city}, {street} {type} {number}")
            address_template = await config.get_setting(
                db, "GEO_ADDRESS_FORMAT_TEMPLATE",
                default="{zip} {city}, {street} {type} {number}."
            )

            # 2. Irányítószám és Város (Auto-learning / Upsert)
            zip_id_query = text("""
                INSERT INTO data.geo_postal_codes (zip_code, city, country_code) 
                VALUES (:z, :c, :cc)
                ON CONFLICT (country_code, zip_code, city) DO UPDATE SET city = EXCLUDED.city
                RETURNING id
            """)
            zip_res = await db.execute(zip_id_query, {"z": zip_code, "c": city, "cc": default_country})
            zip_id = zip_res.scalar()

            # 3. Utca szótár frissítése
            await db.execute(text("""
                INSERT INTO data.geo_streets (postal_code_id, name) VALUES (:zid, :n)
                ON CONFLICT (postal_code_id, name) DO NOTHING
            """), {"zid": zip_id, "n": street_name})

            # 4. Közterület típus (út, utca, köz...)
            await db.execute(text("""
                INSERT INTO data.geo_street_types (name) VALUES (:n) 
                ON CONFLICT (name) DO NOTHING
            """), {"n": street_type.lower()})

            # 5. SZÖVEGES CÍM GENERÁLÁSA SABLON ALAPJÁN (2.2 Újdonság)
            # Megformázzuk az alapcímet az admin sablon szerint
            full_text = address_template.format(
                zip=zip_code, 
                city=city, 
                street=street_name, 
                type=street_type, 
                number=house_number
            )
            
            # Hozzáadjuk az atomizált kiegészítőket, ha vannak
            if stairwell: full_text += f" {stairwell}. lph."
            if floor: full_text += f" {floor}. em."
            if door: full_text += f" {door}. ajtó"

            # 6. Központi Address rekord rögzítése vagy lekérése
            address_query = text("""
                INSERT INTO data.addresses (
                    postal_code_id, street_name, street_type, house_number, 
                    stairwell, floor, door, parcel_id, full_address_text
                )
                VALUES (:zid, :sn, :st, :hn, :sw, :fl, :dr, :pid, :txt)
                ON CONFLICT (postal_code_id, street_name, street_type, house_number, stairwell, floor, door) 
                DO NOTHING
                RETURNING id
            """)
            
            params = {
                "zid": zip_id, "sn": street_name, "st": street_type, 
                "hn": house_number, "sw": stairwell, "fl": floor, 
                "dr": door, "pid": parcel_id, "txt": full_text
            }
            
            res = await db.execute(address_query, params)
            addr_id = res.scalar()

            # 7. Biztonsági keresés: Ha létezett a rekord, de nem kaptunk ID-t a RETURNING-gal
            if not addr_id:
                lookup_query = text("""
                    SELECT id FROM data.addresses 
                    WHERE postal_code_id = :zid 
                      AND street_name = :sn 
                      AND street_type = :st
                      AND house_number = :hn 
                      AND (stairwell IS NOT DISTINCT FROM :sw)
                      AND (floor IS NOT DISTINCT FROM :fl)
                      AND (door IS NOT DISTINCT FROM :dr)
                    LIMIT 1
                """)
                lookup_res = await db.execute(lookup_query, params)
                addr_id = lookup_res.scalar()

            return addr_id

        except Exception as e:
            logger.error(f"GeoService Critical Error: {str(e)}")
            raise ValueError(f"Súlyos hiba a cím normalizálása során. Admin/Séma ellenőrzése javasolt.")