from django.db import models
from django.utils.text import slugify
from account.models import User
from django.urls import reverse
import requests
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from home.models import ShowCaseSlider
from decimal import Decimal
from dirtyfields import DirtyFieldsMixin



class UnitCategoryModel(models.Model):
    name = models.CharField(max_length=50, verbose_name='نام دسته بندی')
    slug = models.SlugField(max_length=50, unique=True,
                            help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید")
    icon = models.ImageField(upload_to='category_model/',
                             verbose_name='آیکون', blank=True, null=True)
    image = models.ImageField(
        upload_to='category_model/', verbose_name='عکس', blank=True, null=True)
    meta_title = models.CharField(
        max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True)
    meta_description = models.TextField(
        max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True)

    class Meta:
        verbose_name = "دسته‌بندی اصلی"
        verbose_name_plural = "دسته‌بندی‌هااصلی"
        indexes = [
            models.Index(fields=['slug'], name='main_category_slug_idx'),
        ]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = 'unit-category-' + slugify(self.name, allow_unicode=True)
        super().save(*args, **kwargs)




class MainCategoryModel(models.Model):
    name = models.CharField(max_length=50, verbose_name='نام دسته بندی')
    slug = models.SlugField(max_length=50, unique=True,
                            help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید")
    icon = models.ImageField(upload_to='category_model/',
                             verbose_name='آیکون', blank=True, null=True)
    image = models.ImageField(
        upload_to='category_model/', verbose_name='عکس', blank=True, null=True)
    meta_title = models.CharField(
        max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True)
    meta_description = models.TextField(
        max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True)
    video = models.FileField(upload_to='category_videos/',
                             blank=True, null=True, verbose_name='ویدیو')
    parent = models.ForeignKey(UnitCategoryModel, on_delete=models.SET_NULL,
                               related_name='maincategorys', verbose_name='دسته‌بندی والد', null=True)
    show_in_home = models.BooleanField(default=False, verbose_name='نمایش در خانه')
    class Meta:
        verbose_name = "دسته‌بندی اصلی"
        verbose_name_plural = "دسته‌بندی‌هااصلی"
        indexes = [
            models.Index(fields=['slug'], name='unit_category_slug_idx'),
        ]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = 'category-' + slugify(self.name, allow_unicode=True)
        super().save(*args, **kwargs)


class SubCategoryModel(models.Model):
    name = models.CharField(max_length=50, verbose_name='نام دسته بندی')
    slug = models.SlugField(max_length=50, unique=True,
                            help_text="اسم دسته را برای مسیر به انگلیسی و بدون فاصله وارد کنید")
    image = models.ImageField(
        upload_to='category_model/', verbose_name='عکس', blank=True, null=True)
    icon = models.ImageField(upload_to='category_model/',
                             verbose_name='آیکون', blank=True, null=True)
    meta_title = models.CharField(
        max_length=60, verbose_name="عنوان متا", help_text="عنوان متا برای SEO", blank=True, null=True)
    meta_description = models.TextField(
        max_length=160, verbose_name="توضیحات متا", help_text="توضیحات متا برای SEO", blank=True, null=True)
    parent = models.ForeignKey(MainCategoryModel, on_delete=models.SET_NULL,
                               related_name='subcategorys', verbose_name='دسته‌بندی والد', null=True)

    class Meta:
        verbose_name = "زیر دسته‌بندی"
        verbose_name_plural = "زیر دسته‌بندی‌ها"
        indexes = [
            models.Index(fields=['slug'], name='sub_category_slug_idx'),
            models.Index(fields=['parent'], name='sub_category_parent_idx'),
        ]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        # Ensure slug is present and unique. If a slug (auto or custom) would
        # collide with an existing product, append a numeric suffix.
        if not self.slug:
            base_slug = slugify(self.name, allow_unicode=True)
        else:
            # Normalize a provided slug
            base_slug = slugify(self.slug, allow_unicode=True)

        slug_candidate = base_slug
        counter = 1
        # Exclude self.pk to allow updating the same instance
        while ProductModel.objects.filter(slug=slug_candidate).exclude(pk=self.pk).exists():
            slug_candidate = f"{base_slug}-{counter}"
            counter += 1

        self.slug = slug_candidate
        super().save(*args, **kwargs)


class DollorModel(models.Model):
    price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True, verbose_name='قیمت دلار')
    defualt_price = models.DecimalField(
        max_digits=10, decimal_places=2, null=True, blank=True, default=80000.0, verbose_name='قیمت دستی')
    # these fields will avoid dublicate of this model
    unique = (('unique', 'unique'),)
    unique_filed = models.CharField(
        max_length=20, choices=unique, unique=True, default='unique')

    def __str__(self):
        return str(self.price)

    def save(self, *args, **kwargs):
        if not self.price:
            self.update_price()
        super().save(*args, **kwargs)

    def update_price(self):
        self.price = self.get_usd_price()

    def get_usd_price(self):
        try:
            api_usd = "https://api.nobitex.ir/v2/orderbook/USDTIRT"
            response = requests.get(api_usd)
            data = response.json()
            price = int(data["lastTradePrice"])
            price_in_usd = price / 10.0
            print('\n\nprice from api \n\n')
        except Exception as e:
            return self.defualt_price

        return price_in_usd

    class Meta:
        verbose_name = 'مدل دلار'
        verbose_name_plural = 'مدل دلار'
        indexes = [
            models.Index(fields=['unique_filed'],
                         name='dollor_unique_field_idx'),
        ]


class InPackItems(models.Model):
    item_title = models.CharField(max_length=50)
    cover = models.ImageField(
        upload_to='product_items/', verbose_name='کاور ایتم')

    class Meta:
        verbose_name = 'ایتم داخل پک'
        verbose_name_plural = 'ایتم های داخل پک'

    def __str__(self):
        return self.item_title


class ProductModel(models.Model):
    name = models.CharField(max_length=255, verbose_name='نام')
    description = models.TextField(verbose_name='توضیحات')
    image = models.ImageField(upload_to='product_main/', null=True, blank=True)
    rating = models.PositiveIntegerField(default=0, verbose_name='امتیاز')
    show_in_trends = models.BooleanField(default=False, verbose_name='نمایش در ترند ها')
    show_in_most_viewed = models.BooleanField(default=False, verbose_name='نمایش در پر بازدید ها')
    show_in_lot_of_discount = models.BooleanField(default=False, verbose_name='نمایش در پر تخفیف ها')
    show_in_top_seller = models.BooleanField(default=False, verbose_name='نمایش در پر فروش ها')
    view = models.IntegerField(default=0, verbose_name='بازدید')
    slug = models.SlugField(max_length=255, unique=True, blank=True, null=True, allow_unicode=True,
                            verbose_name='نام یکتا', help_text="این فیلد را خالی بگذارید")
    meta_description = models.CharField(
        max_length=300, blank=True, null=True, help_text='این فیلد را حتما پر کنید', verbose_name='متا دیسکریپشن')
    meta_keywords = models.CharField(max_length=300, blank=True, null=True,
                                     help_text='این فیلد را حتما پر کنید', verbose_name='متا کیورد')
    meta_rating = models.FloatField(
        default=5, help_text='امتیاز محصول', verbose_name='متا ریتینگ')
    created_at = models.DateTimeField(
        auto_now_add=True, verbose_name='زمان ثبت محصول')
    category = models.ForeignKey(SubCategoryModel,  null=True, on_delete=models.SET_NULL,
                                 related_name='products', verbose_name='دسته بندی محصول')
    related_products = models.ManyToManyField(
        'self', blank=True ,verbose_name='محصولات مرتبط')
    shop = models.ForeignKey('account.ShopModel', on_delete=models.CASCADE,
                             related_name='products', verbose_name='فروشگاه', blank=True, null=True)
    show_in_bot = models.BooleanField(
        default=False, verbose_name='نمایش در ربات')
    bot_banner = models.TextField(
        null=True, blank=True, verbose_name='بنر ربات')

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name, allow_unicode=True)
        super().save(*args, **kwargs)
        
    def get_best_deal_variant(self):
        return self.variants.order_by("price", "-discount").first()

    class Meta:
        verbose_name = 'محصول'
        verbose_name_plural = 'محصولات'
        ordering = ['category', 'name']
        indexes = [
            models.Index(fields=['slug'], name='product_slug_idx'),
            models.Index(fields=['category'], name='product_category_idx'),
            models.Index(fields=['name'], name='product_name_idx'),
            models.Index(fields=['created_at'], name='product_created_at_idx'),
            models.Index(fields=['show_in_trends'], name='product_show_in_trends_idx'),
            models.Index(fields=['show_in_most_viewed'], name='product_most_viewed_idx'),
            models.Index(fields=['show_in_lot_of_discount'], name='product_lot_of_discount_idx'),
            models.Index(fields=['show_in_top_seller'], name='product_show_in_top_seller_idx'),
            models.Index(fields=['category', 'created_at'],
                         name='product_category_created_idx'),
            models.Index(fields=['category', 'name'],
                         name='product_category_name_idx'),
        ]


class ProductDetailCategory(models.Model):
    title = models.CharField(max_length=40, verbose_name='عنوان')

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = 'دسته بندی جزيات'
        verbose_name_plural = 'دسته بندی های جزيیات'
        indexes = [
            models.Index(fields=['title'], name='detail_category_title_idx'),
        ]


class CommentModel(models.Model):
    product = models.ForeignKey(
        ProductModel, on_delete=models.CASCADE, related_name='comments', verbose_name='محصول')
    title = models.CharField(max_length=50)
    content = models.TextField(verbose_name='محتوای نظر')
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, verbose_name='کاربر')
    timestamp = models.DateTimeField(
        auto_now_add=True, verbose_name='زمان ثبت کامنت')
    status_types = (
        ('reviewed_and_confirmed', 'بررسی و تایید شده'),
        ('reviewed_and_rejected', 'بررسی شده و رد شده'),
        ('not_reviwed', 'بررسی نشده'),
    )
    review_status = models.CharField(
        default='not_reviwed', verbose_name='نشان دادن کامنت', max_length=30, choices=status_types)

    class Meta:
        verbose_name = 'نظر'
        verbose_name_plural = 'نظرات'
        indexes = [
            models.Index(fields=['product'], name='comment_product_idx'),
            models.Index(fields=['review_status'],
                         name='comment_review_status_idx'),
            models.Index(fields=['product', 'review_status'],
                         name='comment_product_status_idx'),
            models.Index(fields=['user'], name='comment_user_idx'),
            models.Index(fields=['timestamp'], name='comment_timestamp_idx'),
        ]

    def __str__(self):
        return f"{self.user}-{self.content[:30]}"


class AttributeType(models.Model):
    name = models.CharField(verbose_name='نام نوع متغییر', max_length=100)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'نوع متغییر محصول'
        verbose_name_plural = 'نوع های متغییر محصول'


class AttributeValue(models.Model):
    attribute_type = models.ForeignKey(
        AttributeType, on_delete=models.CASCADE, blank=True, null=True)
    value = models.CharField(
        verbose_name='مقدار نوع اتربیوت', max_length=100, blank=True, null=True)

    class Meta:
        unique_together = ('attribute_type', 'value')
        verbose_name = 'مقدار متغییر محصول'
        verbose_name_plural = 'مقدار های متغییر محصول'

    def __str__(self):
        return f"{self.attribute_type}: {self.value}"


class ProductImageModel(models.Model):
    name = models.CharField(max_length=30, verbose_name='نام عکس')
    image = models.ImageField(upload_to='product_images/')

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = 'عکس محصولات'
        verbose_name_plural = 'عکس های محصولات'


class ProductDetailModel(models.Model):
    name = models.CharField(max_length=50, verbose_name='نام جزيیات',
                            help_text='این متن فقط برای راحتی در استفاده از پنل ادمین میباشد')
    detail_category = models.ForeignKey(
        ProductDetailCategory, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات')

    class Meta:
        verbose_name = 'جزیات محصول'
        verbose_name_plural = 'جزیات محصول ها'
        indexes = [
            models.Index(fields=['detail_category'],
                         name='product_detail_category_idx'),
        ]

    def __str__(self):
        return f'جزيیات محصول {self.detail_category.title} - {self.name}'


class DetailModel(models.Model):
    title = models.CharField(max_length=50, verbose_name='عنوان')
    detail_text1 = models.CharField(max_length=150, verbose_name='متن جزیات ۱')
    detail_text2 = models.CharField(
        max_length=150, verbose_name='متن جزیات ۲', blank=True, null=True)
    detail_text3 = models.CharField(
        max_length=150, verbose_name='متن جزیات ۳', blank=True, null=True)
    detail_text4 = models.CharField(
        max_length=150, verbose_name='متن جزیات ۴', blank=True, null=True)
    detail_model = models.ForeignKey(
        ProductDetailModel, on_delete=models.CASCADE, verbose_name='دسته بندی جزيات', related_name='details')

    def __str__(self):
        return f'{self.title}'

    class Meta:
        verbose_name = 'مدل جزیات'
        verbose_name_plural = 'مدل های جزیات'
        indexes = [
            models.Index(fields=['detail_model'], name='detail_model_idx'),
            models.Index(fields=['title'], name='detail_title_idx'),
        ]


class ProductVariant(DirtyFieldsMixin, models.Model):
    product = models.ForeignKey(
        ProductModel, on_delete=models.CASCADE, related_name='variants', verbose_name='محصول')
    product_attributes = models.ManyToManyField(
        AttributeValue, verbose_name='ویژگی‌ها', related_name='variant')
    in_stock = models.PositiveIntegerField(
        default=0, verbose_name='تعداد موجود', help_text='تعداد موجودی برای این تنوع محصول')
    price = models.PositiveBigIntegerField(
        verbose_name='قیمت محاسبه شده محصول', blank=True, null=True)
    input_price = models.PositiveBigIntegerField(
        default=0, verbose_name='قیمت ورودی محصول', help_text='قیمت محصول با سودش در صورتی که نوسان دلاری روشن باشد قیمت به دلار محسابه و ذخیره می شود و قیمت نهایی در قیمت محاسبه شده ذخیره میشود')
    min_price = models.PositiveBigIntegerField(
        verbose_name='قیمت کف', help_text='این قیمت برای کف قیمتی محصول در نظر گرفته میشود و حتی با نوسان دلاری قیمت از این کمتر نخواهد شد')
    profit = models.PositiveBigIntegerField(
        default=0, verbose_name='سود (تومان)', help_text='مقدار سود به ازای این محصول (نکته این مقدار به قیمت اصلی اضافه نخواهد شد و فقط برای محاسبه ی تخفیف ها میباشد)')
    special_discount_percent = models.SmallIntegerField(
        default=0, verbose_name='درصد تخفیف ویژه', help_text='درصدی که از سود برای محاسبه تخفیف ویژه استفاده می‌شود')
    currency_type = (
        ('dollor', 'با نوسان دلاری'),
        ('toman', 'بدون نوسان'),
    )
    in_pack_items = models.ManyToManyField(
        InPackItems, blank=True, verbose_name='ایتم های داخل پک')
    sell = models.IntegerField(default=0, verbose_name='فروش')
    currency = models.CharField(
        verbose_name='نوع نوسان', max_length=20, choices=currency_type, default='toman')
    price_in_dollor = models.DecimalField(
        max_digits=15, decimal_places=8, blank=True, null=True, 
        verbose_name='قیمت به دلار', help_text='قیمت محصول به دلار (محاسبه خودکار)')
    discount = models.SmallIntegerField(default=0, verbose_name='درصد تخفیف', help_text='این درصد از قیمت نهایی محصول کسر میگردد')
    color = models.CharField(
        verbose_name='رنگ', max_length=7, blank=True, null=True)
    images = models.ManyToManyField(ProductImageModel, verbose_name='عکس ها')
    video = models.FileField(upload_to='product_videos/',
                             blank=True, null=True, verbose_name='ویدیو')
    details = models.ManyToManyField(
        ProductDetailModel, verbose_name='جزییات محصول', related_name='product')
    slider_category = models.ForeignKey(
        ShowCaseSlider, verbose_name='دسته بندی پورسانتی', blank=True, null=True, on_delete=models.CASCADE)
    created_at = models.DateTimeField(
        auto_now_add=True, verbose_name='زمان ثبت محصول')

    class Meta:
        verbose_name = 'تنوع محصول'
        verbose_name_plural = 'تنوع‌های محصول'
        indexes = [
            models.Index(fields=['product', 'price', 'created_at'],
                         name='idx_product_price_created'),
            models.Index(fields=['in_stock', 'discount'],
                         name='idx_stock_discount'),
            models.Index(fields=['created_at'], name='idx_created'),
            models.Index(fields=['price'], name='idx_price'),
            models.Index(fields=['discount'],
                         name='product_variant_discount_idx'),
            models.Index(fields=['in_stock'],
                         name='product_variant_in_stock_idx'),
            models.Index(fields=['product'],
                         name='product_variant_product_idx'),
            models.Index(fields=['product', 'in_stock'],
                         name='variant_product_stock_idx'),
            models.Index(fields=['product', 'discount'],
                         name='variant_product_discount_idx'),
        ]

    def __str__(self):
        return f"{self.product.name} - {', '.join(str(attr) for attr in self.product_attributes.all())}"

    @property
    def price_before_discount(self):
        return self.price

    @property
    def price_after_discount(self):
        return self.price - self.discount_amount

    @property
    def discount_amount(self):
        return self.price * (self.discount / 100)

    @property
    def special_discount_amount_per_unit(self):
        """Calculate special discount amount per unit as profit * special_discount_percent / 100."""
        try:
            return int(self.profit * (self.special_discount_percent / 100))
        except Exception:
            return 0

    def round_toman(self, value):
        """Round to nearest 1000 toman (e.g., 89123 -> 89000, 89500 -> 90000)"""
        return round(value / 1000) * 1000

    def set_or_update_price(self, dollor_price=None):
        if not dollor_price:
            dollor_object, _ = DollorModel.objects.get_or_create(
                unique_filed='unique')
            dollor_price = dollor_object.price

        if dollor_price is None:
            raise ValidationError(
                {"dollor_price": "The 'dollor_price' must be provided in the context for dollar pricing."})


        if self.currency == 'toman':
            toman_price = self.input_price
            # Clear dollar price when currency is toman
            self.price_in_dollor = None
        elif self.currency == 'dollor':
            # Only recalculate dollar price if input_price has changed
            if self.is_dirty(check_relationship=False) and 'input_price' in self.get_dirty_fields(check_relationship=False):
                self.price_in_dollor = Decimal(str(self.input_price)) / Decimal(str(dollor_price))
            
            # Always recalculate Toman price using stored dollar price and current rate
            if self.price_in_dollor:
                # toman_price = self.price_in_dollor * Decimal(str(dollor_price))
                toman_price = Decimal(str(self.price_in_dollor)) * Decimal(str(dollor_price))
            else:
                # Fallback if price_in_dollor is not set yet
                toman_price = self.input_price
        else:
            toman_price = self.input_price
            self.price_in_dollor = None

        self.price = max(self.round_toman(toman_price), self.min_price)

    def save(self, *args, **kwargs):
        self.set_or_update_price()
        super().save(*args, **kwargs)
