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

from app.services.config_service import config # 2.0 Dinamikus konfig
from app.db.session import AsyncSessionLocal
from app.models.identity.address import GeoPostalCode, GeoStreet, GeoStreetType, Address

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 system.geo_streets s
            JOIN system.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) - SELECT, majd INSERT
            stmt = select(GeoPostalCode).where(
                and_(
                    GeoPostalCode.country_code == default_country,
                    GeoPostalCode.zip_code == zip_code,
                    GeoPostalCode.city == city
                )
            )
            existing_pc = (await db.execute(stmt)).scalar_one_or_none()
            
            if existing_pc:
                zip_id = existing_pc.id
            else:
                # 2. Beszúrás ha nem létezik
                new_pc = GeoPostalCode(
                    country_code=default_country,
                    zip_code=zip_code,
                    city=city
                )
                db.add(new_pc)
                await db.flush()
                zip_id = new_pc.id

            # 3. Utca szótár frissítése (SELECT, majd INSERT)
            stmt_street = select(GeoStreet).where(
                and_(
                    GeoStreet.postal_code_id == zip_id,
                    GeoStreet.name == street_name
                )
            )
            existing_street = (await db.execute(stmt_street)).scalar_one_or_none()
            if not existing_street:
                new_street = GeoStreet(postal_code_id=zip_id, name=street_name)
                db.add(new_street)
                await db.flush()

            # 4. Közterület típus (SELECT, majd INSERT)
            stmt_type = select(GeoStreetType).where(GeoStreetType.name == street_type.lower())
            existing_type = (await db.execute(stmt_type)).scalar_one_or_none()
            if not existing_type:
                new_type = GeoStreetType(name=street_type.lower())
                db.add(new_type)
                await db.flush()

            # 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 (SELECT, majd INSERT)
            stmt_addr = select(Address).where(
                and_(
                    Address.postal_code_id == zip_id,
                    Address.street_name == street_name,
                    Address.street_type == street_type,
                    Address.house_number == house_number,
                    Address.stairwell == stairwell,
                    Address.floor == floor,
                    Address.door == door
                )
            )
            existing_addr = (await db.execute(stmt_addr)).scalar_one_or_none()
            if existing_addr:
                addr_id = existing_addr.id
            else:
                new_addr = Address(
                    postal_code_id=zip_id,
                    street_name=street_name,
                    street_type=street_type,
                    house_number=house_number,
                    stairwell=stairwell,
                    floor=floor,
                    door=door,
                    parcel_id=parcel_id,
                    full_address_text=full_text,
                    created_at=datetime.now(timezone.utc)
                )
                db.add(new_addr)
                await db.flush()
                addr_id = new_addr.id

            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.")