# /opt/docker/dev/service_finder/backend/app/services/marketplace_service.py
"""
Marketplace Service – Verifikált Szerviz Értékelések (Social 3) logikája.
"""

import logging
import uuid
import asyncio
from datetime import datetime, timedelta
from typing import Optional, Dict, Any, List, Tuple
from sqlalchemy import select, and_, func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.exc import IntegrityError

from app.models import ServiceReview
from app.models.marketplace.service import ServiceProfile
from app.models.identity import User
from app.models import FinancialLedger
from app.models.system import SystemParameter
from app.schemas.social import ServiceReviewCreate, ServiceReviewResponse
from app.services.system_service import get_system_parameter

logger = logging.getLogger(__name__)


async def create_verified_review(
    db: AsyncSession,
    service_id: int,
    user_id: int,
    transaction_id: uuid.UUID,
    review_data: ServiceReviewCreate,
) -> ServiceReviewResponse:
    """
    Verifikált szerviz értékelés létrehozása.
    Csak igazolt pénzügyi tranzakció után, időablakon belül, egy tranzakcióra egyszer.
    
    Args:
        db: AsyncSession
        service_id: A szerviz ID (service_profiles.id)
        user_id: A felhasználó ID (users.id)
        transaction_id: A pénzügyi tranzakció UUID (financial_ledger.transaction_id)
        review_data: Értékelési adatok (ratings, comment)
    
    Returns:
        ServiceReviewResponse
    
    Raises:
        ValueError: Ha a validáció sikertelen.
        IntegrityError: Ha a tranzakció már értékelve van.
    """
    # 1. Ellenőrzés: Létezik‑e a szerviz?
    service = await db.get(ServiceProfile, service_id)
    if not service:
        raise ValueError(f"Service {service_id} not found")
    
    # 2. Ellenőrzés: Létezik‑e a felhasználó?
    user = await db.get(User, user_id)
    if not user:
        raise ValueError(f"User {user_id} not found")
    
    # 3. Ellenőrzés: A tranzakció létezik és a felhasználóhoz tartozik?
    stmt = select(FinancialLedger).where(
        FinancialLedger.transaction_id == transaction_id,
        FinancialLedger.user_id == user_id
    )
    result = await db.execute(stmt)
    transaction = result.scalar_one_or_none()
    if not transaction:
        raise ValueError(f"Transaction {transaction_id} not found or does not belong to user {user_id}")
    
    # 4. Ellenőrzés: A tranzakció időpontja a REVIEW_WINDOW_DAYS‑on belül van?
    window_days = await get_system_parameter(db, "REVIEW_WINDOW_DAYS", default=30)
    window_limit = datetime.now() - timedelta(days=window_days)
    if transaction.created_at < window_limit:
        raise ValueError(f"Transaction is older than {window_days} days, review window expired")
    
    # 5. Ellenőrzés: Már létezik‑e értékelés ehhez a tranzakcióhoz?
    existing_review = await db.execute(
        select(ServiceReview).where(ServiceReview.transaction_id == transaction_id)
    )
    if existing_review.scalar_one_or_none():
        raise IntegrityError(f"Transaction {transaction_id} already has a review")
    
    # 6. Értékelési dimenziók validálása (1‑10)
    ratings = [
        review_data.price_rating,
        review_data.quality_rating,
        review_data.time_rating,
        review_data.communication_rating
    ]
    for rating in ratings:
        if not (1 <= rating <= 10):
            raise ValueError("All ratings must be between 1 and 10")
    
    # 7. ServiceReview létrehozása
    review = ServiceReview(
        service_id=service_id,
        user_id=user_id,
        transaction_id=transaction_id,
        price_rating=review_data.price_rating,
        quality_rating=review_data.quality_rating,
        time_rating=review_data.time_rating,
        communication_rating=review_data.communication_rating,
        comment=review_data.comment,
        is_verified=True
    )
    db.add(review)
    await db.commit()
    await db.refresh(review)
    
    # 8. Háttér‑aggregátor indítása (aszinkron)
    asyncio.create_task(update_service_rating_aggregates(db, service_id))
    
    logger.info(f"Verified review created: id={review.id}, service={service_id}, user={user_id}")
    
    return ServiceReviewResponse.from_orm(review)


async def update_service_rating_aggregates(db: AsyncSession, service_id: int) -> None:
    """
    Frissíti a szerviz aggregált értékelési adatait (service_profiles táblában).
    Ez a függvény háttérben futhat (pl. Celery vagy asyncio task).
    """
    # Összes verifikált értékelés lekérdezése a szervizhez
    stmt = select(
        func.count(ServiceReview.id).label("count"),
        func.avg(ServiceReview.price_rating).label("price_avg"),
        func.avg(ServiceReview.quality_rating).label("quality_avg"),
        func.avg(ServiceReview.time_rating).label("time_avg"),
        func.avg(ServiceReview.communication_rating).label("communication_avg"),
        func.max(ServiceReview.created_at).label("last_review_at")
    ).where(
        and_(
            ServiceReview.service_id == service_id,
            ServiceReview.is_verified == True
        )
    )
    result = await db.execute(stmt)
    row = result.fetchone()
    
    if not row or row.count == 0:
        # Nincs értékelés, alapértékek
        price_avg = quality_avg = time_avg = communication_avg = None
        count = 0
        last_review_at = None
    else:
        count = row.count
        price_avg = float(row.price_avg) if row.price_avg else None
        quality_avg = float(row.quality_avg) if row.quality_avg else None
        time_avg = float(row.time_avg) if row.time_avg else None
        communication_avg = float(row.communication_avg) if row.communication_avg else None
        last_review_at = row.last_review_at
    
    # Trust‑score súlyozás: a felhasználók trust‑score‑jának átlaga
    trust_stmt = select(func.avg(User.trust_score)).join(
        ServiceReview, ServiceReview.user_id == User.id
    ).where(
        and_(
            ServiceReview.service_id == service_id,
            ServiceReview.is_verified == True
        )
    )
    trust_result = await db.execute(trust_stmt)
    avg_trust = trust_result.scalar() or 50.0  # alapérték 50
    
    # Trust‑score befolyási tényező
    trust_factor = await get_system_parameter(db, "TRUST_SCORE_INFLUENCE_FACTOR", default=1.0)
    trust_weight = 1.0 + (avg_trust / 100.0) * trust_factor
    
    # Súlyozott összpontszám számítása
    weights = await get_system_parameter(db, "REVIEW_RATING_WEIGHTS", default={
        "price": 0.25,
        "quality": 0.35,
        "time": 0.20,
        "communication": 0.20
    })
    weighted_score = 0.0
    if price_avg:
        weighted_score += price_avg * weights.get("price", 0.25)
    if quality_avg:
        weighted_score += quality_avg * weights.get("quality", 0.35)
    if time_avg:
        weighted_score += time_avg * weights.get("time", 0.20)
    if communication_avg:
        weighted_score += communication_avg * weights.get("communication", 0.20)
    
    weighted_score *= trust_weight
    
    # ServiceProfile frissítése
    service = await db.get(ServiceProfile, service_id)
    if service:
        service.rating_verified_count = count
        service.rating_price_avg = price_avg
        service.rating_quality_avg = quality_avg
        service.rating_time_avg = time_avg
        service.rating_communication_avg = communication_avg
        service.rating_overall = weighted_score
        service.last_review_at = last_review_at
        await db.commit()
        logger.debug(f"Updated rating aggregates for service {service_id}: count={count}, overall={weighted_score:.2f}")


async def get_service_reviews(
    db: AsyncSession,
    service_id: int,
    skip: int = 0,
    limit: int = 20,
    verified_only: bool = True
) -> Tuple[List[ServiceReviewResponse], int]:
    """
    Szerviz értékeléseinek lapozható listázása.
    
    Args:
        db: AsyncSession
        service_id: A szerviz ID
        skip: Lapozási offset
        limit: Maximális darabszám
        verified_only: Csak verifikált értékelések
    
    Returns:
        (reviews, total_count)
    """
    conditions = [ServiceReview.service_id == service_id]
    if verified_only:
        conditions.append(ServiceReview.is_verified == True)
    
    # Összes darabszám
    count_stmt = select(func.count(ServiceReview.id)).where(*conditions)
    total_result = await db.execute(count_stmt)
    total = total_result.scalar()
    
    # Lapozott lekérdezés
    stmt = select(ServiceReview).where(*conditions).order_by(
        ServiceReview.created_at.desc()
    ).offset(skip).limit(limit)
    result = await db.execute(stmt)
    reviews = result.scalars().all()
    
    return [ServiceReviewResponse.from_orm(r) for r in reviews], total


async def can_user_review_service(
    db: AsyncSession,
    user_id: int,
    service_id: int
) -> Tuple[bool, Optional[str]]:
    """
    Ellenőrzi, hogy a felhasználó értékelheti‑e a szervizt.
    
    Returns:
        (can_review, reason)
    """
    # 1. Van‑e már értékelése a szervizre?
    existing_stmt = select(ServiceReview).where(
        ServiceReview.user_id == user_id,
        ServiceReview.service_id == service_id
    )
    existing = await db.execute(existing_stmt)
    if existing.scalar_one_or_none():
        return False, "User already reviewed this service"
    
    # 2. Van‑e a felhasználónak tranzakciója a szervizzel?
    # Megjegyzés: A tranzakció‑szerviz kapcsolat jelenleg nincs tárolva.
    # Ehhez a FinancialLedger‑ben kellene egy service_id mező, vagy
    # egy kapcsolótábla. Most csak annyit ellenőrzünk, hogy van‑e bármilyen
    # tranzakció a felhasználónak, ami még nem értékelt.
    # TODO: Később pontosítani a tranzakció‑szerviz kapcsolatot.
    
    return True, None