from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from fastapi import HTTPException, status
from typing import List, Optional, Dict, Any

from app.models.review_models import Review
from app.models.user_models import User
from app.models.catalog_models import Product
from app.schemas.review_schemas import ReviewCreate, ReviewUpdate


def get_review(db: Session, review_id: int) -> Optional[Review]:
    return db.query(Review).filter(Review.id == review_id).first()


def get_product_reviews(
    db: Session, 
    product_id: int, 
    skip: int = 0, 
    limit: int = 100,
    approved_only: bool = True
) -> List[Review]:
    query = db.query(Review).filter(Review.product_id == product_id)
    
    if approved_only:
        query = query.filter(Review.is_approved == True)
    
    return query.order_by(Review.created_at.desc()).offset(skip).limit(limit).all()


def get_user_reviews(db: Session, user_id: int, skip: int = 0, limit: int = 100) -> List[Review]:
    return db.query(Review).filter(Review.user_id == user_id).order_by(Review.created_at.desc()).offset(skip).limit(limit).all()


def get_all_reviews(
    db: Session, 
    skip: int = 0, 
    limit: int = 100, 
    approved_only: bool = False
) -> List[Review]:
    query = db.query(Review)
    
    if approved_only:
        query = query.filter(Review.is_approved == True)
    
    return query.order_by(Review.created_at.desc()).offset(skip).limit(limit).all()


def create_review(db: Session, review: ReviewCreate, user_id: int) -> Review:
    # Проверяем, что продукт существует
    product = db.query(Product).filter(Product.id == review.product_id).first()
    if not product:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Продукт не найден"
        )
    
    # Проверяем, не оставлял ли пользователь уже отзыв на этот продукт
    existing_review = db.query(Review).filter(
        Review.user_id == user_id,
        Review.product_id == review.product_id
    ).first()
    
    if existing_review:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Вы уже оставили отзыв на этот продукт"
        )
    
    # Проверяем, покупал ли пользователь этот продукт (для verified_purchase)
    # Это можно реализовать, проверив наличие завершенных заказов с этим продуктом
    # Для простоты пока устанавливаем is_verified_purchase = False
    is_verified_purchase = False
    
    # Создаем отзыв
    db_review = Review(
        user_id=user_id,
        product_id=review.product_id,
        rating=review.rating,
        title=review.title,
        comment=review.comment,
        is_verified_purchase=is_verified_purchase,
        is_approved=False  # По умолчанию отзыв требует одобрения
    )
    
    try:
        db.add(db_review)
        db.commit()
        db.refresh(db_review)
        return db_review
    except IntegrityError:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при создании отзыва"
        )


def update_review(db: Session, review_id: int, review: ReviewUpdate, user_id: int, is_admin: bool = False) -> Review:
    db_review = get_review(db, review_id)
    if not db_review:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Отзыв не найден"
        )
    
    # Проверяем права на редактирование отзыва
    if not is_admin and db_review.user_id != user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Недостаточно прав для редактирования этого отзыва"
        )
    
    # Обновляем только предоставленные поля
    update_data = review.dict(exclude_unset=True)
    
    # Обычные пользователи не могут менять статус одобрения
    if not is_admin and "is_approved" in update_data:
        del update_data["is_approved"]
    
    # Применяем обновления
    for key, value in update_data.items():
        setattr(db_review, key, value)
    
    try:
        db.commit()
        db.refresh(db_review)
        return db_review
    except IntegrityError:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при обновлении отзыва"
        )


def delete_review(db: Session, review_id: int, user_id: int, is_admin: bool = False) -> bool:
    db_review = get_review(db, review_id)
    if not db_review:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Отзыв не найден"
        )
    
    # Проверяем права на удаление отзыва
    if not is_admin and db_review.user_id != user_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Недостаточно прав для удаления этого отзыва"
        )
    
    try:
        db.delete(db_review)
        db.commit()
        return True
    except Exception:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при удалении отзыва"
        )


def approve_review(db: Session, review_id: int) -> Review:
    db_review = get_review(db, review_id)
    if not db_review:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Отзыв не найден"
        )
    
    db_review.is_approved = True
    
    try:
        db.commit()
        db.refresh(db_review)
        return db_review
    except IntegrityError:
        db.rollback()
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Ошибка при одобрении отзыва"
        )


def get_review_with_user(db: Session, review_id: int) -> Dict[str, Any]:
    review = get_review(db, review_id)
    if not review:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Отзыв не найден"
        )
    
    # Получаем пользователя
    user = db.query(User).filter(User.id == review.user_id).first()
    
    return {
        "id": review.id,
        "user_id": review.user_id,
        "product_id": review.product_id,
        "rating": review.rating,
        "title": review.title,
        "comment": review.comment,
        "is_verified_purchase": review.is_verified_purchase,
        "is_approved": review.is_approved,
        "created_at": review.created_at,
        "updated_at": review.updated_at,
        "user_email": user.email if user else "Неизвестный пользователь"
    }


def get_product_rating(db: Session, product_id: int) -> Dict[str, Any]:
    # Проверяем, что продукт существует
    product = db.query(Product).filter(Product.id == product_id).first()
    if not product:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Продукт не найден"
        )
    
    # Получаем все одобренные отзывы для продукта
    reviews = db.query(Review).filter(
        Review.product_id == product_id,
        Review.is_approved == True
    ).all()
    
    # Рассчитываем средний рейтинг и количество отзывов
    total_reviews = len(reviews)
    if total_reviews == 0:
        return {
            "product_id": product_id,
            "average_rating": 0,
            "total_reviews": 0,
            "rating_distribution": {
                "1": 0,
                "2": 0,
                "3": 0,
                "4": 0,
                "5": 0
            }
        }
    
    # Рассчитываем распределение рейтингов
    rating_distribution = {
        "1": 0,
        "2": 0,
        "3": 0,
        "4": 0,
        "5": 0
    }
    
    total_rating = 0
    for review in reviews:
        total_rating += review.rating
        rating_distribution[str(review.rating)] += 1
    
    average_rating = total_rating / total_reviews
    
    return {
        "product_id": product_id,
        "average_rating": round(average_rating, 1),
        "total_reviews": total_reviews,
        "rating_distribution": rating_distribution
    } 