from decimal import Decimal, ROUND_HALF_UP

from django.shortcuts import render, get_object_or_404
from django.views import View
from django.views.generic import ListView, DetailView
from django.http import HttpRequest, JsonResponse
from django.db.models import Avg, Count, F, Q, Max
from django.template.loader import render_to_string
from django.core.exceptions import FieldError
from django.views.decorators.http import require_POST

# مدل‌های اپلیکیشن خودمان (product_module)
from .models import (
    Product,
    ProductCategory,
    ProductBrand,
    ProductVisit,
    ProductGallery,
    SubCategory,
    Color,
    ProductComment,
)

# مدل‌های اپلیکیشن‌های دیگر
from site_module.models import SiteBanner

# ابزارهای کمکی
from project_utils.http_service import get_client_ip
from project_utils.convertors import group_list


# ============================================================
# Product List View
# ============================================================
class ProductListView(ListView):
    template_name = "product_module/product_list.html"
    model = Product
    context_object_name = "products"
    ordering = ["-price"]
    paginate_by = 10

    @staticmethod
    def clean_price(value):
        """
        قیمت ورودی از GET را تمیز می‌کند.
        مثال: 12,500,000 -> Decimal("12500000")
        """
        if value in (None, ""):
            return None

        try:
            normalized = str(value).replace(",", "").strip()
            if not normalized:
                return None

            price = Decimal(normalized)
            if price < 0:
                return None

            return price.quantize(Decimal("0"), rounding=ROUND_HALF_UP)
        except Exception:
            return None

    def get_price_values(self):
        start_price = self.clean_price(self.request.GET.get("start_price"))
        end_price = self.clean_price(self.request.GET.get("end_price"))

        # اگر کاربر بازه را برعکس وارد کرد، جابه‌جا شود.
        if (
            start_price is not None
            and end_price is not None
            and start_price > end_price
        ):
            start_price, end_price = end_price, start_price

        return start_price, end_price

    def get_queryset(self):
        qs = (
            Product.objects
            .filter(is_active=True, is_delete=False)
            .select_related("brand", "subcategory")
        )

        category_name = self.kwargs.get("cat") or self.request.GET.get("cat")
        brand_name = self.kwargs.get("brand")

        # فیلتر دسته
        if category_name:
            qs = qs.filter(
                subcategory__category__url_title__iexact=category_name
            )

        # فیلتر برند
        if brand_name:
            qs = qs.filter(
                brand__url_title__iexact=brand_name
            )

        # فیلتر قیمت
        start_price, end_price = self.get_price_values()
        if start_price is not None:
            qs = qs.filter(price__gte=start_price)
        if end_price is not None:
            qs = qs.filter(price__lte=end_price)

        # فیلتر رنگ
        color = self.request.GET.get("color", "").strip()
        if color:
            if color.isdigit():
                qs = qs.filter(colors__id=int(color))
            else:
                qs = qs.filter(colors__slug__iexact=color)

        return qs.distinct()

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        category_name = self.kwargs.get("cat")
        brand_name = self.kwargs.get("brand")

        # واکشی شناسه‌های تمام محصولات فیلتر شده، نه فقط صفحه جاری
        filtered_products_ids = self.get_queryset().values_list("id", flat=True)

        # شمارش دقیق رنگ‌ها فقط بر اساس محصولات فیلتر شده
        colors_qs = (
            Color.objects
            .filter(is_active=True)
            .annotate(
                count=Count(
                    "products",
                    filter=Q(
                        products__id__in=filtered_products_ids,
                        products__is_active=True,
                        products__is_delete=False,
                    ),
                    distinct=True,
                )
            )
            .filter(count__gt=0)
            .order_by("-count", "name")
            .distinct()
        )

        context["colors"] = colors_qs
        context["selected_color"] = self.request.GET.get("color")

        # بیشترین قیمت برای اسلایدر قیمت
        valid_products = Product.objects.filter(
            is_active=True,
            is_delete=False,
        )

        if category_name:
            valid_products = valid_products.filter(
                subcategory__category__url_title__iexact=category_name
            )

        if brand_name:
            valid_products = valid_products.filter(
                brand__url_title__iexact=brand_name
            )

        db_max_price = (
            valid_products.aggregate(max_price=Max("price"))["max_price"]
            or Decimal("0")
        )

        start_price, end_price = self.get_price_values()

        context["db_max_price"] = db_max_price
        context["start_price"] = (
            start_price if start_price is not None else Decimal("0")
        )
        context["end_price"] = (
            end_price if end_price is not None else db_max_price
        )

        # بنرها
        context["banners"] = SiteBanner.objects.filter(
            is_active=True,
            position__iexact=SiteBanner.SiteBannerPositions.product_list,
        )

        # محصولات بدون تخفیف
        context["non_discounted_products"] = Product.objects.filter(
            Q(price_before_discount__isnull=True)
            | Q(price__gte=F("price_before_discount")),
            is_active=True,
            is_delete=False,
        )

        # دسته‌بندی‌ها به همراه ساب‌کتگوری‌ها
        context["categories"] = (
            ProductCategory.objects
            .filter(is_active=True, is_delete=False)
            .prefetch_related("subcategories")
        )

        # تعداد محصولات هر ساب‌کتگوری
        subcategories_count_qs = (
            SubCategory.objects
            .filter(
                is_active=True,
                category__is_active=True,
                category__is_delete=False,
            )
            .annotate(
                products_count=Count(
                    "product",
                    filter=Q(
                        product__is_active=True,
                        product__is_delete=False,
                    ),
                    distinct=True,
                )
            )
        )

        context["subcategories_count"] = {
            item.id: item.products_count for item in subcategories_count_qs
        }

        # برندها به همراه فیلتر دسته و تعداد محصولات هر برند
        brands = ProductBrand.objects.filter(
            products__is_active=True,
            products__is_delete=False,
            is_active=True,
        )

        if category_name:
            brands = brands.filter(
                products__subcategory__category__url_title__iexact=category_name
            )

        context["brands"] = (
            brands
            .annotate(
                products_count=Count(
                    "products",
                    filter=Q(
                        products__is_active=True,
                        products__is_delete=False,
                    ),
                    distinct=True,
                )
            )
            .distinct()
        )

        if category_name:
            context["subcategories"] = SubCategory.objects.filter(
                category__url_title__iexact=category_name,
                is_active=True,
            )
        else:
            context["subcategories"] = SubCategory.objects.none()

        # محصولات محبوب بر اساس بازدید
        context["popular_products"] = (
            Product.objects
            .filter(is_active=True, is_delete=False)
            .annotate(visit_count=Count("visits", distinct=True))
            .order_by("-visit_count", "-price")[:12]
        )

        return context


# ============================================================
# Product Detail View
# ============================================================
class ProductDetailView(DetailView):
    template_name = "product_module/product_detail.html"
    model = Product

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        product = self.object
        request = self.request

        # علاقه‌مندی
        context["is_favorite"] = str(product.id) in request.session.get(
            "favorite_products",
            [],
        )

        # بنر صفحه محصول
        context["banners"] = SiteBanner.objects.filter(
            is_active=True,
            position__iexact=SiteBanner.SiteBannerPositions.product_detail,
        )

        # گالری
        gallery = list(ProductGallery.objects.filter(product_id=product.id))
        gallery.insert(0, product)
        context["product_galleries_group"] = group_list(gallery, 3)

        # ویژگی‌ها / مشخصات فنی
        context["spec_groups"] = product.spec_groups.prefetch_related("items").all()

        # میانگین امتیاز
        context["average_rating"] = (
            ProductComment.objects
            .filter(product=product, is_active=True)
            .aggregate(avg=Avg("rating"))["avg"]
            or 0
        )

        # لیست نظرات تایید شده
        context["comments"] = (
            ProductComment.objects
            .filter(product_id=product.id, is_active=True)
            .order_by("-id")
        )

        # ثبت بازدید
        user_ip = get_client_ip(request)
        user_id = request.user.id if request.user.is_authenticated else None

        if not ProductVisit.objects.filter(
            ip__iexact=user_ip,
            product_id=product.id,
        ).exists():
            ProductVisit.objects.create(
                ip=user_ip,
                user_id=user_id,
                product_id=product.id,
            )

        return context


# ============================================================
# Favorite Product
# ============================================================
class AddProductFavorite(View):
    def post(self, request):
        product_id = request.POST.get("product_id")

        if not product_id:
            return JsonResponse(
                {
                    "status": "error",
                    "message": "product_id is required",
                },
                status=400,
            )

        product_id = str(product_id)
        favorites = request.session.get("favorite_products", [])

        if product_id in favorites:
            favorites.remove(product_id)
            status = "removed"
        else:
            favorites.append(product_id)
            status = "added"

        request.session["favorite_products"] = favorites
        request.session.modified = True

        return JsonResponse(
            {
                "status": status,
                "count": len(favorites),
            }
        )


class RemoveFavorite(View):
    def post(self, request):
        product_id = request.POST.get("product_id")
        favorites = request.session.get("favorite_products", [])

        if product_id in favorites:
            favorites.remove(product_id)

        request.session["favorite_products"] = favorites
        request.session.modified = True

        return JsonResponse(
            {
                "status": "removed",
                "count": len(favorites),
            }
        )


# ============================================================
# Product Categories Component
# ============================================================
def product_categories_component(request: HttpRequest):
    categories = ProductCategory.objects.filter(
        is_active=True,
        is_delete=False,
    )

    return render(
        request,
        "product_module/components/product_categories_component.html",
        {
            "categories": categories,
        },
    )


# ============================================================
# Product Brands Component
# ============================================================
def product_brands_component(request: HttpRequest):
    brands = (
        ProductBrand.objects
        .annotate(products_count=Count("products"))
        .filter(is_active=True)
    )

    return render(
        request,
        "product_module/components/product_brands_component.html",
        {
            "brands": brands,
        },
    )


# ============================================================
# Best Seller Products (اصلاح تداخل و یکپارچه‌سازی)
# ============================================================
class BestSellerProductsView(ListView):
    model = Product
    template_name = "product_module/best_seller_products.html"
    context_object_name = "products"
    paginate_by = 12

    def get_queryset(self):
        qs = Product.objects.filter(
            is_active=True,
            is_delete=False
        ).select_related('brand', 'subcategory')

        try:
            # تلاش برای مرتب‌سازی بر اساس تعداد فروش
            qs = qs.order_by('-sales_count', '-id')
        except FieldError:
            # مرتب‌سازی جایگزین در صورت نبود فیلد sales_count
            qs = qs.annotate(
                visit_count=Count('visits', distinct=True)
            ).order_by('-visit_count', '-id')

        return qs

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['page_title'] = 'همه محصولات پرفروش'
        
        # واکشی و اضافه کردن محصولات دارای تخفیف فعال
        context["discount_products"] = (
            Product.objects.filter(
                price_before_discount__isnull=False,
                price__lt=F("price_before_discount"),
                is_active=True,
                is_delete=False,
            )
            .select_related("brand", "subcategory")
            .order_by("-sales_count", "-id")[:12]  # محدود کردن برای ابزارک‌ها در صورت نیاز
        )
        return context


# ============================================================
# Subcategory Products Page
# ============================================================
def subcategory_products(request, slug):
    subcategory = get_object_or_404(SubCategory, url_title__iexact=slug)

    products = Product.objects.filter(
        subcategory=subcategory,
        is_active=True,
        is_delete=False,
    )

    return render(
        request,
        "product_module/subcategory.html",
        {
            "subcategory": subcategory,
            "products": products,
        },
    )


# ============================================================
# Ajax Search
# ============================================================
def product_search(request):
    query = request.GET.get("q", "").strip()

    products = (
        Product.objects
        .filter(
            Q(title__icontains=query) | Q(description__icontains=query),
            is_active=True,
            is_delete=False,
        )
        if query
        else Product.objects.none()
    )

    if request.headers.get("x-requested-with") == "XMLHttpRequest":
        results = [
            {
                "title": p.title,
                "url": p.get_absolute_url(),
                "image": p.image.url if p.image else "",
            }
            for p in products[:6]
        ]
        return JsonResponse(results, safe=False)

    return render(
        request,
        "product_module/search_results.html",
        {
            "products": products,
            "query": query,
        },
    )


# ============================================================
# Add Product Comment
# ============================================================
@require_POST
def add_product_comment(request):
    if not request.user.is_authenticated:
        return JsonResponse(
            {
                "status": "not_auth",
                "message": "لطفاً ابتدا وارد شوید",
            },
            status=403,
        )

    product_id = request.POST.get("product_id")
    comment_text = request.POST.get("text", "").strip()
    rating = request.POST.get("rating")

    try:
        product_id = int(product_id)
    except (TypeError, ValueError):
        return JsonResponse(
            {
                "status": "invalid_product",
                "message": "محصول نامعتبر است",
            },
            status=400,
        )

    if not Product.objects.filter(pk=product_id).exists():
        return JsonResponse(
            {
                "status": "invalid_product",
                "message": "محصول نامعتبر است",
            },
            status=400,
        )

    if not comment_text:
        return JsonResponse(
            {
                "status": "empty_text",
                "message": "لطفاً متن نظر خود را وارد کنید",
            },
            status=400,
        )

    try:
        rating = int(rating)
    except (TypeError, ValueError):
        return JsonResponse(
            {
                "status": "invalid_rating",
                "message": "امتیاز نامعتبر است",
            },
            status=400,
        )

    if rating not in range(1, 6):
        return JsonResponse(
            {
                "status": "invalid_rating",
                "message": "امتیاز باید بین ۱ تا ۵ باشد",
            },
            status=400,
        )

    try:
        ProductComment.objects.create(
            product_id=product_id,
            user=request.user,
            text=comment_text,
            rating=rating,
            is_active=True,
        )

        comments = (
            ProductComment.objects
            .filter(product_id=product_id, is_active=True)
            .order_by("-create_date")
        )

        comments_html = render_to_string(
            "includes/product_comments_partial.html",
            {"comments": comments},
            request=request,
        )

        return JsonResponse(
            {
                "status": "success",
                "message": "نظر شما با موفقیت ثبت شد",
                "body": comments_html,
            }
        )
    except Exception as exc:
        print(f"Error in add_comment: {exc}")
        return JsonResponse(
            {
                "status": "error",
                "message": "خطایی در سرور رخ داد",
            },
            status=500,
        )


# ============================================================
# Favorite List View
# ============================================================
class FavoriteListView(ListView):
    template_name = "product_module/favorite_list.html"
    context_object_name = "products"

    def get_queryset(self):
        favorites = self.request.session.get("favorite_products", [])
        favorite_ids = [int(i) for i in favorites if str(i).isdigit()]

        return Product.objects.filter(
            id__in=favorite_ids,
            is_active=True,
            is_delete=False,
        )
