from sqlalchemy.orm import Session
from fastapi import HTTPException, status, UploadFile
from typing import List, Dict, Any
import os
import uuid
import shutil
from pathlib import Path

from app.config import settings
from app.repositories import catalog_repo, review_repo
from app.schemas.catalog_schemas import (
    CategoryCreate, CategoryUpdate, 
    ProductCreate, ProductUpdate,
    ProductVariantCreate, ProductVariantUpdate,
    ProductImageCreate, ProductImageUpdate,
    CollectionCreate, CollectionUpdate
)


# Сервисы для коллекций
def create_collection(db: Session, collection: CollectionCreate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Collection as CollectionSchema
    
    new_collection = catalog_repo.create_collection(db, collection)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    collection_schema = CollectionSchema.model_validate(new_collection)
    return {"collection": collection_schema}


def update_collection(db: Session, collection_id: int, collection: CollectionUpdate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Collection as CollectionSchema
    
    updated_collection = catalog_repo.update_collection(db, collection_id, collection)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    collection_schema = CollectionSchema.model_validate(updated_collection)
    return {"collection": collection_schema}


def delete_collection(db: Session, collection_id: int) -> Dict[str, Any]:
    success = catalog_repo.delete_collection(db, collection_id)
    return {"success": success}


def get_collections(db: Session, skip: int = 0, limit: int = 100) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Collection as CollectionSchema
    
    collections = catalog_repo.get_collections(db, skip, limit)
    # Преобразуем объекты SQLAlchemy в схемы Pydantic
    collections_schema = [CollectionSchema.model_validate(collection) for collection in collections]
    return {"collections": collections_schema, "total": len(collections_schema)}


# Сервисы каталога
def create_category(db: Session, category: CategoryCreate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Category as CategorySchema
    
    new_category = catalog_repo.create_category(db, category)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    category_schema = CategorySchema.model_validate(new_category)
    return {"category": category_schema}


def update_category(db: Session, category_id: int, category: CategoryUpdate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Category as CategorySchema
    
    updated_category = catalog_repo.update_category(db, category_id, category)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    category_schema = CategorySchema.model_validate(updated_category)
    return {"category": category_schema}


def delete_category(db: Session, category_id: int) -> Dict[str, Any]:
    success = catalog_repo.delete_category(db, category_id)
    return {"success": success}


def get_category_tree(db: Session) -> List[Dict[str, Any]]:
    from app.schemas.catalog_schemas import Category as CategorySchema
    from sqlalchemy import func
    from app.models.catalog_models import Product
    
    # Получаем все категории верхнего уровня
    root_categories = catalog_repo.get_categories(db, parent_id=None)
    
    result = []
    for category in root_categories:
        # Преобразуем объект SQLAlchemy в схему Pydantic
        category_schema = CategorySchema.model_validate(category)
        # Получаем количество продуктов в категории
        products_count = db.query(func.count(Product.id)).filter(
            Product.category_id == category.id,
            Product.is_active == True
        ).scalar() or 0
        
        # Рекурсивно получаем подкатегории
        category_dict = category_schema.model_dump()
        subcategories, subcategories_products_count = _get_subcategories(db, category.id)
        category_dict["subcategories"] = subcategories
        category_dict["products_count"] = products_count + subcategories_products_count
        result.append(category_dict)
    
    return result


def _get_subcategories(db: Session, parent_id: int) -> tuple[List[Dict[str, Any]], int]:
    from app.schemas.catalog_schemas import Category as CategorySchema
    from sqlalchemy import func
    from app.models.catalog_models import Product
    
    subcategories = catalog_repo.get_categories(db, parent_id=parent_id)
    
    result = []
    total_products_count = 0
    
    for category in subcategories:
        # Преобразуем объект SQLAlchemy в схему Pydantic
        category_schema = CategorySchema.model_validate(category)
        
        # Получаем количество продуктов в категории
        products_count = db.query(func.count(Product.id)).filter(
            Product.category_id == category.id,
            Product.is_active == True
        ).scalar() or 0
        
        category_dict = category_schema.model_dump()
        sub_subcategories, sub_products_count = _get_subcategories(db, category.id)
        
        total_products_in_category = products_count + sub_products_count
        total_products_count += total_products_in_category
        
        category_dict["subcategories"] = sub_subcategories
        category_dict["products_count"] = total_products_in_category
        
        result.append(category_dict)
    
    return result, total_products_count


def create_product(db: Session, product: ProductCreate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Product as ProductSchema
    
    new_product = catalog_repo.create_product(db, product)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    product_schema = ProductSchema.model_validate(new_product)
    return {"product": product_schema}


def update_product(db: Session, product_id: int, product: ProductUpdate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Product as ProductSchema
    
    updated_product = catalog_repo.update_product(db, product_id, product)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    product_schema = ProductSchema.model_validate(updated_product)
    return {"product": product_schema}


def delete_product(db: Session, product_id: int) -> Dict[str, Any]:
    success = catalog_repo.delete_product(db, product_id)
    return {"success": success}


def get_product_details(db: Session, product_id: int) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import Product as ProductSchema, Category as CategorySchema
    from app.schemas.catalog_schemas import ProductVariant as ProductVariantSchema
    from app.schemas.catalog_schemas import ProductImage as ProductImageSchema
    from app.schemas.catalog_schemas import Collection as CollectionSchema
    
    product = catalog_repo.get_product(db, product_id)
    if not product:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Продукт не найден"
        )
    
    # Получаем варианты продукта
    variants = catalog_repo.get_product_variants(db, product_id)
    
    # Получаем изображения продукта
    images = catalog_repo.get_product_images(db, product_id)
    
    # Получаем рейтинг продукта
    rating = review_repo.get_product_rating(db, product_id)
    
    # Получаем отзывы продукта
    reviews = review_repo.get_product_reviews(db, product_id, limit=5)
    
    # Преобразуем объекты SQLAlchemy в схемы Pydantic
    product_schema = ProductSchema.model_validate(product)
    variants_schema = [ProductVariantSchema.model_validate(variant) for variant in variants]
    images_schema = [ProductImageSchema.model_validate(image) for image in images]
    
    # Добавляем информацию о коллекции, если она есть
    collection_schema = None
    if product.collection_id:
        collection = catalog_repo.get_collection(db, product.collection_id)
        if collection:
            collection_schema = CollectionSchema.model_validate(collection)
    
    return {
        "product": product_schema,
        "variants": variants_schema,
        "images": images_schema,
        "collection": collection_schema,
        "rating": rating,
        "reviews": reviews
    }


def add_product_variant(db: Session, variant: ProductVariantCreate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import ProductVariant as ProductVariantSchema
    
    new_variant = catalog_repo.create_product_variant(db, variant)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    variant_schema = ProductVariantSchema.model_validate(new_variant)
    return {"variant": variant_schema}


def update_product_variant(db: Session, variant_id: int, variant: ProductVariantUpdate) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import ProductVariant as ProductVariantSchema
    
    updated_variant = catalog_repo.update_product_variant(db, variant_id, variant)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    variant_schema = ProductVariantSchema.model_validate(updated_variant)
    return {"variant": variant_schema}


def delete_product_variant(db: Session, variant_id: int) -> Dict[str, Any]:
    success = catalog_repo.delete_product_variant(db, variant_id)
    return {"success": success}


def upload_product_image(db: Session, product_id: int, file: UploadFile, is_primary: bool = False) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import ProductImage as ProductImageSchema
    
    # Проверяем, что продукт существует
    product = catalog_repo.get_product(db, product_id)
    if not product:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Продукт не найден"
        )
    
    # Проверяем расширение файла
    file_extension = file.filename.split(".")[-1].lower()
    if file_extension not in settings.ALLOWED_UPLOAD_EXTENSIONS:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=f"Неподдерживаемый формат файла. Разрешены: {', '.join(settings.ALLOWED_UPLOAD_EXTENSIONS)}"
        )
    
    # Создаем директорию для загрузок, если она не существует
    upload_dir = Path(settings.UPLOAD_DIRECTORY) / "products" / str(product_id)
    upload_dir.mkdir(parents=True, exist_ok=True)
    
    # Генерируем уникальное имя файла
    unique_filename = f"{uuid.uuid4()}.{file_extension}"
    file_path = upload_dir / unique_filename
    
    # Сохраняем файл
    with file_path.open("wb") as buffer:
        shutil.copyfileobj(file.file, buffer)
    
    # Создаем запись об изображении в БД
    image_data = ProductImageCreate(
        product_id=product_id,
        image_url=f"/uploads/products/{product_id}/{unique_filename}",
        alt_text=file.filename,
        is_primary=is_primary
    )
    
    new_image = catalog_repo.create_product_image(db, image_data)
    
    # Преобразуем объект SQLAlchemy в схему Pydantic
    image_schema = ProductImageSchema.model_validate(new_image)
    return {"image": image_schema}


def update_product_image(db: Session, image_id: int, is_primary: bool) -> Dict[str, Any]:
    from app.schemas.catalog_schemas import ProductImage as ProductImageSchema
    
    updated_image = catalog_repo.update_product_image(db, image_id, is_primary)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    image_schema = ProductImageSchema.model_validate(updated_image)
    return {"image": image_schema}


def delete_product_image(db: Session, image_id: int) -> Dict[str, Any]:
    # Получаем информацию об изображении перед удалением
    image = catalog_repo.get_product_image(db, image_id)
    if not image:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Изображение не найдено"
        )
    
    # Удаляем запись из БД
    success = catalog_repo.delete_product_image(db, image_id)
    
    # Удаляем файл с диска
    if success:
        try:
            # Получаем путь к файлу из URL
            file_path = Path(settings.UPLOAD_DIRECTORY) / image.image_url.lstrip("/uploads/")
            if file_path.exists():
                file_path.unlink()
        except Exception:
            # Если не удалось удалить файл, просто логируем ошибку
            # В реальном приложении здесь должно быть логирование
            pass
    
    return {"success": success} 