from decimal import Decimal, ROUND_HALF_UP

from django.core.exceptions import FieldError
from django.db.models import Count, Q, Max, Prefetch
from django.shortcuts import render
from django.views.generic import TemplateView

from article_module.models import Article
from product_module.models import Product, ProductCategory, ProductBrand
from site_module.models import (
    SiteFeature,
    SiteSetting,
    FooterLinkBox,
    Slider,
    SiteBanner,
    AboutUs,
)
from project_utils.convertors import group_list
from .models import ProductSlider, Feature


# -------------------------------------------------------
# BASE DISCOUNT VIEW
# -------------------------------------------------------
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP

class BaseDiscountView(TemplateView):
    def to_decimal(self, value, default=Decimal("0")):
        if value in (None, ""):
            return default
        try:
            s = str(value).strip().replace(",", "")
            if s == "":
                return default
            return Decimal(s)
        except (InvalidOperation, ValueError, TypeError):
            return default

    def calculate_discount(self, product):
        original_raw = (
            getattr(product, "price_before_discount", None)
            or getattr(product, "original_price", None)
            or 0
        )
        price_raw = getattr(product, "price", 0) or 0

        original = self.to_decimal(original_raw)
        price = self.to_decimal(price_raw)

        if original > price and original > 0:
            percent = ((original - price) / original) * Decimal("100")
            product.discount_percent = percent.quantize(Decimal("0"), rounding=ROUND_HALF_UP)
        else:
            product.discount_percent = Decimal("0")

        product.price_difference = max(original - price, Decimal("0"))

        # مهم: روی فیلد/پراپرتی مدل مقداردهی نکن
        # چون اگر original_price @property باشد AttributeError می‌دهد
        product.original_price_display = original  # فقط برای template

        return product



# -------------------------------------------------------
# HOME PAGE
# -------------------------------------------------------
class HomeView(BaseDiscountView):
    template_name = "home_module/index_page.html"

    # -------------------------
    # PRICE FILTER
    # -------------------------
    def clean_price_value(self, value):
        if not value:
            return None
        try:
            value = str(value).replace(",", "").strip()
            return Decimal(value).quantize(Decimal("0"), rounding=ROUND_HALF_UP)
        except Exception:
            return None

    def get_price_filter(self):
        start_raw = self.request.GET.get("start_price")
        end_raw = self.request.GET.get("end_price")

        start = self.clean_price_value(start_raw)
        end = self.clean_price_value(end_raw)

        price_filter = Q()
        if start is not None:
            price_filter &= Q(price__gte=start)
        if end is not None:
            price_filter &= Q(price__lte=end)

        return start, end, price_filter

    def get_color_filter(self):
        color_slug = self.request.GET.get("color")
        if color_slug:
            return Q(colors__slug=color_slug), color_slug
        return Q(), None

    # -------------------------
    # BASE PRODUCTS QUERY
    # -------------------------
    def get_active_products(self, filters=Q()):
        qs = Product.objects.filter(
            is_active=True,
            is_delete=False
        ).select_related("brand", "subcategory")

        if filters:
            qs = qs.filter(filters)

        return qs

    # -------------------------
    # LATEST PRODUCTS
    # -------------------------
    def get_latest_products(self, qs):
        products = [
            self.calculate_discount(p)
            for p in qs.order_by("-id")[:8]
        ]
        return group_list(products)

    # -------------------------
    # MOST VISITED
    # -------------------------
    def get_most_visited(self, qs):
        products = [
            self.calculate_discount(p)
            for p in qs.annotate(
                visit_count=Count("visits", distinct=True)
            ).order_by("-visit_count", "-id")[:8]
        ]
        return group_list(products)

    # -------------------------
    # BEST SELLERS
    # -------------------------
    def get_best_sellers(self, qs):
        selected_cat = self.request.GET.get("best_cat")

        if selected_cat:
            qs = qs.filter(
                subcategory__category__url_title__iexact=selected_cat
            )

        try:
            qs = qs.order_by("-sales_count", "-id")
        except FieldError:
            qs = qs.annotate(
                visit_count=Count("visits", distinct=True)
            ).order_by("-visit_count", "-id")

        return [self.calculate_discount(p) for p in qs[:8]]

    # -------------------------
    # CATEGORY PRODUCTS
    # -------------------------
    def get_category_products(self, filters=Q()):
        active_products_prefetch = Prefetch(
            "products",
            queryset=Product.objects.filter(
                is_active=True,
                is_delete=False
            ).filter(filters).order_by("-id"),
            to_attr="prefetched_active_products"
        )

        categories = (
            ProductCategory.objects
            .filter(is_active=True, is_delete=False)
            .prefetch_related(active_products_prefetch)
            .annotate(
                products_count=Count(
                    "products",
                    filter=Q(
                        products__is_active=True,
                        products__is_delete=False
                    ),
                    distinct=True
                )
            )
            .filter(products_count__gt=0)[:6]
        )

        data = []
        for cat in categories:
            products = cat.prefetched_active_products[:4]
            data.append({
                "id": cat.id,
                "title": cat.title,
                "url_title": cat.url_title,
                "products": [self.calculate_discount(p) for p in products]
            })

        return data

    # -------------------------
    # OFFERS
    # -------------------------
    def get_offers(self, qs):
        offers_qs = qs.filter(
            Q(is_flash_offer=True) | Q(is_amazing_offer=True)
        ).order_by("-id")

        unique_products = []
        seen_ids = set()

        for product in offers_qs:
            if product.id not in seen_ids:
                unique_products.append(self.calculate_discount(product))
                seen_ids.add(product.id)

        return unique_products[:10]

    # -------------------------
    # MAIN CONTEXT
    # -------------------------
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        start_price, end_price, price_filter = self.get_price_filter()
        color_filter, selected_color = self.get_color_filter()
        combined_filter = price_filter & color_filter

        active_products = self.get_active_products(combined_filter)

        context["selected_color"] = selected_color
        context["selected_best_cat"] = self.request.GET.get("best_cat")

        context["features"] = SiteFeature.objects.filter(is_active=True).order_by("order")
        context["extra_features"] = Feature.objects.filter(is_active=True)
        context["sliders"] = Slider.objects.filter(is_active=True)

        context["banner_top"] = SiteBanner.objects.filter(
            is_active=True,
            position__iexact="index_side_top"
        ).first()

        context["banner_bottom"] = SiteBanner.objects.filter(
            is_active=True,
            position__iexact="index_side_bottom"
        ).first()

        context["latest_products"] = self.get_latest_products(active_products)
        context["most_visit_products"] = self.get_most_visited(active_products)
        context["best_sellers"] = self.get_best_sellers(active_products)
        context["categories_products"] = self.get_category_products(combined_filter)
        context["special_offers"] = self.get_offers(active_products)

        context["brands"] = (
            ProductBrand.objects
            .filter(is_active=True)
            .annotate(
                products_count=Count(
                    "products",
                    filter=Q(
                        products__is_active=True,
                        products__is_delete=False
                    ),
                    distinct=True
                )
            )
            .filter(products_count__gt=0)
        )

        slider_items = (
            ProductSlider.objects
            .filter(is_active=True)
            .select_related("product")
            .order_by("order")
        )

        context["slider_products"] = [
            self.calculate_discount(item.product)
            for item in slider_items if item.product
        ]

        context["articles"] = Article.objects.filter(
            is_active=True
        ).order_by("-create_date")[:8]

        context["site_setting"] = SiteSetting.objects.filter(is_main_setting=True).first()
        context["about"] = AboutUs.objects.first()

        max_price = Product.objects.filter(
            is_active=True,
            is_delete=False
        ).aggregate(Max("price"))["price__max"]

        context["db_max_price"] = max_price if max_price else 1000000
        context["start_price"] = start_price if start_price is not None else 0
        context["end_price"] = end_price if end_price is not None else context["db_max_price"]

        context["popular_products"] = (
            Product.objects
            .filter(is_active=True, is_delete=False)
            .annotate(visit_count=Count("visits", distinct=True))
            .order_by("-visit_count", "-id")[:12]
        )

        context["best_categories"] = (
            ProductCategory.objects
            .filter(is_active=True, is_delete=False)
            .annotate(
                products_count=Count(
                    "products",
                    filter=Q(
                        products__is_active=True,
                        products__is_delete=False
                    ),
                    distinct=True
                )
            )
            .filter(products_count__gt=0)
        )

        return context


# -------------------------------------------------------
# HEADER COMPONENT
# -------------------------------------------------------
def site_header_component(request):
    setting = SiteSetting.objects.filter(is_main_setting=True).first()
    return render(
        request,
        "shared/site_header_component.html",
        {"site_setting": setting}
    )


# -------------------------------------------------------
# FOOTER COMPONENT
# -------------------------------------------------------
def site_footer_component(request):
    setting = SiteSetting.objects.filter(is_main_setting=True).first()
    footer_link_boxes = FooterLinkBox.objects.all()
    return render(
        request,
        "shared/site_footer_component.html",
        {
            "site_setting": setting,
            "footer_link_boxes": footer_link_boxes,
        }
    )


# -------------------------------------------------------
# NAVBAR CATEGORY CONTEXT PROCESSOR
# -------------------------------------------------------
def navbar_categories(request):
    categories = ProductCategory.objects.filter(
        is_active=True
    ).prefetch_related("subcategories")
    return {"navbar_categories": categories}


# -------------------------------------------------------
# FEATURES COMPONENT
# -------------------------------------------------------
def features_component(request):
    features = Feature.objects.filter(is_active=True)
    return render(request, "path_to_your_template/features.html", {"features": features})


# -------------------------------------------------------
# OFFERS PAGE
# -------------------------------------------------------
class OffersView(BaseDiscountView):
    template_name = "home_module/offers_page.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        special_offers_qs = (
            Product.objects
            .filter(is_active=True, is_delete=False)
            .filter(Q(is_amazing_offer=True) | Q(is_flash_offer=True))
            .distinct()
            .order_by("-id")
        )

        special_offers = []
        for p in special_offers_qs:
            p.final_price = p.price
            special_offers.append(self.calculate_discount(p))

        context["special_offers"] = special_offers
        return context
