from django.db import models
from django.contrib.auth.models import (
    AbstractBaseUser,
    PermissionsMixin,
    BaseUserManager,
)
from django.utils import timezone
from django.utils.text import slugify


# =========================================================
# COMMON / BASE MODEL
# =========================================================


class BaseModel(models.Model):
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    is_active = models.BooleanField(default=True)
    is_deleted = models.BooleanField(default=False)
    extra_data = models.JSONField(default=dict, blank=True, null=True)

    class Meta:
        abstract = True


# =========================================================
# USER MANAGER
# =========================================================


class UserManager(BaseUserManager):
    def create_user(self, email, phone, full_name, password=None, **extra_fields):
        if not email:
            raise ValueError("Email is required.")

        email = self.normalize_email(email)

        user = self.model(email=email, phone=phone, full_name=full_name, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self, email, phone, full_name, password=None, **extra_fields):
        extra_fields.setdefault("is_staff", True)
        extra_fields.setdefault("is_superuser", True)
        extra_fields.setdefault("is_active", True)

        if extra_fields.get("is_staff") is not True:
            raise ValueError("Superuser must have is_staff=True.")

        if extra_fields.get("is_superuser") is not True:
            raise ValueError("Superuser must have is_superuser=True.")

        return self.create_user(email, phone, full_name, password, **extra_fields)


# =========================================================
# USER MODEL
# =========================================================


class User(AbstractBaseUser, PermissionsMixin, BaseModel):
    GENDER_CHOICES = (
        ("male", "Male"),
        ("female", "Female"),
        ("other", "Other"),
    )
    ROLE_CHOICES = (

    ("customer", "Customer"),

    ("admin", "Admin"),

    ("warehouse", "Warehouse"),

    ("delivery", "Delivery"),
    )

    full_name = models.CharField(max_length=150)
    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=20, unique=True)
    profile_image = models.ImageField(upload_to="users/profile/", blank=True, null=True)
    gender = models.CharField(
        max_length=20, choices=GENDER_CHOICES, blank=True, null=True
    )
    date_of_birth = models.DateField(blank=True, null=True)
    role = models.CharField(

    max_length=50,

    choices=ROLE_CHOICES,

    default="customer",
    )

    is_email_verified = models.BooleanField(default=False)
    is_phone_verified = models.BooleanField(default=False)

    is_staff = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = ["phone", "full_name"]

    class Meta:
        db_table = "user"
        ordering = ["-created_at"]

    def __str__(self):
        return self.email


# =========================================================
# OTP VERIFICATION MODEL
# =========================================================


class OTPVerification(BaseModel):
    OTP_TYPE_CHOICES = (
        ("signup", "Signup"),
        ("forgot_password", "Forgot Password"),
        ("email_verification", "Email Verification"),
        ("phone_verification", "Phone Verification"),
    )

    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name="otp_records",
        blank=True,
        null=True,
    )
    email_or_phone = models.CharField(max_length=255)
    otp_code = models.CharField(max_length=10)
    otp_type = models.CharField(max_length=50, choices=OTP_TYPE_CHOICES)
    is_used = models.BooleanField(default=False)
    expires_at = models.DateTimeField()

    class Meta:
        db_table = "otp_verification"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.email_or_phone} - {self.otp_type}"

    def is_expired(self):
        return timezone.now() > self.expires_at

    # =========================================================


# CATEGORY / BRAND / PRODUCT MODELS
# =========================================================


class Category(BaseModel):
    name = models.CharField(max_length=120)
    slug = models.SlugField(max_length=150, unique=True, blank=True, null=True)
    image = models.ImageField(upload_to="categories/", blank=True, null=True)
    banner_image = models.ImageField(
        upload_to="categories/banner/", blank=True, null=True
    )
    description = models.TextField(blank=True, null=True)
    sort_order = models.PositiveIntegerField(default=0)
    parent_category = models.ForeignKey(
        "self",
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
        related_name="subcategories",
    )
    show_on_home = models.BooleanField(default=True)

    class Meta:
        db_table = "category"
        ordering = ["sort_order", "name"]

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name


class Brand(BaseModel):
    name = models.CharField(max_length=120)
    slug = models.SlugField(max_length=150, unique=True, blank=True, null=True)
    logo = models.ImageField(upload_to="brands/", blank=True, null=True)
    description = models.TextField(blank=True, null=True)
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "brand"
        ordering = ["sort_order", "name"]

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.name


class Product(BaseModel):
    name = models.CharField(max_length=200)
    slug = models.SlugField(max_length=250, unique=True, blank=True, null=True)
    sku = models.CharField(max_length=100, unique=True)
    short_description = models.CharField(max_length=255, blank=True, null=True)
    description = models.TextField(blank=True, null=True)

    category = models.ForeignKey(
        Category, on_delete=models.CASCADE, related_name="products"
    )
    brand = models.ForeignKey(
        Brand, on_delete=models.SET_NULL, related_name="products", blank=True, null=True
    )

    price = models.DecimalField(max_digits=12, decimal_places=2)
    old_price = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    stock_quantity = models.PositiveIntegerField(default=0)

    rating_avg = models.DecimalField(max_digits=3, decimal_places=2, default=0.00)
    review_count = models.PositiveIntegerField(default=0)

    thumbnail = models.ImageField(
        upload_to="products/thumbnail/", blank=True, null=True
    )

    is_featured = models.BooleanField(default=False)
    is_best_selling = models.BooleanField(default=False)
    is_trending = models.BooleanField(default=False)
    is_returnable = models.BooleanField(default=True)
    is_cod_available = models.BooleanField(default=True)

    warranty_text = models.CharField(max_length=255, blank=True, null=True)
    min_order_quantity = models.PositiveIntegerField(default=1)
    max_order_quantity = models.PositiveIntegerField(default=10)

    class Meta:
        db_table = "product"
        ordering = ["-created_at"]

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.name)
        super().save(*args, **kwargs)

    @property
    def in_stock(self):
        return self.stock_quantity > 0

    @property
    def discount_percentage(self):
        if self.old_price and self.old_price > self.price:
            return round(((self.old_price - self.price) / self.old_price) * 100, 2)
        return 0

    def __str__(self):
        return self.name


class ProductImage(BaseModel):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="product_images"
    )
    image = models.ImageField(upload_to="products/gallery/")
    alt_text = models.CharField(max_length=255, blank=True, null=True)
    sort_order = models.PositiveIntegerField(default=0)
    is_primary = models.BooleanField(default=False)

    class Meta:
        db_table = "product_image"
        ordering = ["sort_order", "id"]

    def __str__(self):
        return f"{self.product.name} - Image"


class ProductSpecification(BaseModel):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="specifications"
    )
    title = models.CharField(max_length=150)
    value = models.CharField(max_length=255)
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "product_specification"
        ordering = ["sort_order", "id"]

    def __str__(self):
        return f"{self.product.name} - {self.title}"


class ProductHighlight(BaseModel):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="highlights"
    )
    title = models.CharField(max_length=255)
    sort_order = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "product_highlight"
        ordering = ["sort_order", "id"]

    def __str__(self):
        return f"{self.product.name} - Highlight"


class Banner(BaseModel):
    BANNER_TYPE_CHOICES = (
        ("home_top", "Home Top"),
        ("offer", "Offer"),
        ("latest", "Latest"),
    )

    title = models.CharField(max_length=150)
    subtitle = models.CharField(max_length=255, blank=True, null=True)
    image = models.ImageField(upload_to="banners/")
    banner_type = models.CharField(
        max_length=50, choices=BANNER_TYPE_CHOICES, default="home_top"
    )
    redirect_type = models.CharField(max_length=50, blank=True, null=True)
    redirect_value = models.CharField(max_length=255, blank=True, null=True)
    sort_order = models.PositiveIntegerField(default=0)
    show_on_home = models.BooleanField(default=True)

    class Meta:
        db_table = "banner"
        ordering = ["sort_order", "-created_at"]

    def __str__(self):
        return self.title


# =========================================================
# WISHLIST / CART / ADDRESS MODELS
# =========================================================


class WishlistItem(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="wishlist_items"
    )
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="wishlisted_by"
    )

    class Meta:
        db_table = "wishlist_item"
        ordering = ["-created_at"]
        unique_together = ("user", "product")

    def __str__(self):
        return f"{self.user.email} - {self.product.name}"


class Cart(BaseModel):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="cart")
    session_key = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        db_table = "cart"
        ordering = ["-created_at"]

    def __str__(self):
        return f"Cart - {self.user.email}"

    @property
    def subtotal(self):
        total = 0
        for item in self.cart_items.filter(is_active=True, is_deleted=False):
            total += item.total_price
        return total

    @property
    def total_items(self):
        total = 0
        for item in self.cart_items.filter(is_active=True, is_deleted=False):
            total += item.quantity
        return total


class CartItem(BaseModel):
    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name="cart_items")
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="cart_items"
    )
    quantity = models.PositiveIntegerField(default=1)
    price_at_time = models.DecimalField(max_digits=12, decimal_places=2)

    class Meta:
        db_table = "cart_item"
        ordering = ["-created_at"]
        unique_together = ("cart", "product")

    def __str__(self):
        return f"{self.cart.user.email} - {self.product.name}"

    @property
    def total_price(self):
        return self.price_at_time * self.quantity


class Address(BaseModel):
    ADDRESS_TYPE_CHOICES = (
        ("home", "Home"),
        ("work", "Work"),
        ("other", "Other"),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="addresses")
    full_name = models.CharField(max_length=150)
    phone = models.CharField(max_length=20)
    alternate_phone = models.CharField(max_length=20, blank=True, null=True)
    address_line_1 = models.CharField(max_length=255)
    address_line_2 = models.CharField(max_length=255, blank=True, null=True)
    landmark = models.CharField(max_length=255, blank=True, null=True)
    city = models.CharField(max_length=100)
    state = models.CharField(max_length=100)
    country = models.CharField(max_length=100, default="India")
    postal_code = models.CharField(max_length=20)
    address_type = models.CharField(
        max_length=20, choices=ADDRESS_TYPE_CHOICES, default="home"
    )
    is_default = models.BooleanField(default=False)

    class Meta:
        db_table = "address"
        ordering = ["-is_default", "-created_at"]

    def __str__(self):
        return f"{self.user.email} - {self.address_line_1}"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if self.is_default:
            Address.objects.filter(user=self.user, is_default=True).exclude(
                id=self.id
            ).update(is_default=False)


# =========================================================
# COUPON / ORDER / PAYMENT MODELS
# =========================================================


class Coupon(BaseModel):
    DISCOUNT_TYPE_CHOICES = (
        ("percentage", "Percentage"),
        ("flat", "Flat"),
    )

    code = models.CharField(max_length=50, unique=True)
    title = models.CharField(max_length=150)
    description = models.TextField(blank=True, null=True)
    discount_type = models.CharField(max_length=20, choices=DISCOUNT_TYPE_CHOICES)
    discount_value = models.DecimalField(max_digits=12, decimal_places=2)
    minimum_order_amount = models.DecimalField(
        max_digits=12, decimal_places=2, default=0.00
    )
    maximum_discount_amount = models.DecimalField(
        max_digits=12, decimal_places=2, default=0.00
    )
    usage_limit = models.PositiveIntegerField(default=0)
    used_count = models.PositiveIntegerField(default=0)
    valid_from = models.DateTimeField()
    valid_to = models.DateTimeField()
    is_first_order_only = models.BooleanField(default=False)

    class Meta:
        db_table = "coupon"
        ordering = ["-created_at"]

    def __str__(self):
        return self.code

    def is_valid_now(self):
        now = timezone.now()
        return (
            self.is_active
            and not self.is_deleted
            and self.valid_from <= now <= self.valid_to
        )


class Order(BaseModel):
    ORDER_STATUS_CHOICES = (
        ("pending", "Pending"),
        ("confirmed", "Confirmed"),
        ("processing", "Processing"),
        ("shipped", "Shipped"),
        ("delivered", "Delivered"),
        ("cancelled", "Cancelled"),
        ("packed", "Packed"),
        ("out_for_delivery", "Out For Delivery"),
    )

    PAYMENT_METHOD_CHOICES = (
        ("razorpay", "Razorpay"),
        ("cod", "Cash on Delivery"),
    )

    PAYMENT_STATUS_CHOICES = (
        ("pending", "Pending"),
        ("paid", "Paid"),
        ("failed", "Failed"),
        ("refunded", "Refunded"),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="orders")
    order_number = models.CharField(max_length=50, unique=True)
    address = models.ForeignKey(
        Address, on_delete=models.SET_NULL, related_name="orders", blank=True, null=True
    )
    status = models.CharField(
        max_length=30, choices=ORDER_STATUS_CHOICES, default="pending"
    )

    subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    discount_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    shipping_charge = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    tax_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)

    payment_method = models.CharField(
        max_length=20, choices=PAYMENT_METHOD_CHOICES, default="razorpay"
    )
    payment_status = models.CharField(
        max_length=20, choices=PAYMENT_STATUS_CHOICES, default="pending"
    )

    coupon = models.ForeignKey(
        Coupon, on_delete=models.SET_NULL, related_name="orders", blank=True, null=True
    )
    notes = models.TextField(blank=True, null=True)

    placed_at = models.DateTimeField(blank=True, null=True)
    delivered_at = models.DateTimeField(blank=True, null=True)
    cancelled_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        db_table = "order"
        ordering = ["-created_at"]

    def __str__(self):
        return self.order_number


class OrderItem(BaseModel):
    order = models.ForeignKey(
        Order, on_delete=models.CASCADE, related_name="order_items"
    )
    product = models.ForeignKey(
        Product,
        on_delete=models.SET_NULL,
        related_name="order_items",
        blank=True,
        null=True,
    )
    product_name = models.CharField(max_length=200)
    product_sku = models.CharField(max_length=100, blank=True, null=True)
    quantity = models.PositiveIntegerField(default=1)
    unit_price = models.DecimalField(max_digits=12, decimal_places=2)
    total_price = models.DecimalField(max_digits=12, decimal_places=2)

    class Meta:
        db_table = "order_item"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.order.order_number} - {self.product_name}"


class PaymentTransaction(BaseModel):
    PAYMENT_GATEWAY_CHOICES = (
        ("razorpay", "Razorpay"),
        ("cod", "Cash on Delivery"),
    )

    PAYMENT_STATUS_CHOICES = (
        ("created", "Created"),
        ("pending", "Pending"),
        ("paid", "Paid"),
        ("failed", "Failed"),
        ("cancelled", "Cancelled"),
        ("refunded", "Refunded"),
    )

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="payment_transactions"
    )
    order = models.ForeignKey(
        Order,
        on_delete=models.SET_NULL,
        related_name="payment_transactions",
        blank=True,
        null=True,
    )
    payment_gateway = models.CharField(
        max_length=20, choices=PAYMENT_GATEWAY_CHOICES, default="razorpay"
    )
    gateway_order_id = models.CharField(max_length=150, blank=True, null=True)
    gateway_payment_id = models.CharField(max_length=150, blank=True, null=True)
    gateway_signature = models.CharField(max_length=255, blank=True, null=True)
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    status = models.CharField(
        max_length=20, choices=PAYMENT_STATUS_CHOICES, default="created"
    )
    paid_at = models.DateTimeField(blank=True, null=True)
    failure_reason = models.TextField(blank=True, null=True)

    class Meta:
        db_table = "payment_transaction"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.user.email} - {self.amount}"






class OrderTrackingEvent(BaseModel):

    EVENT_STATUS_CHOICES = (
        ("placed", "Placed"),
        ("confirmed", "Confirmed"),
        ("processing", "Processing"),
        ("packed", "Packed"),
        ("shipped", "Shipped"),
        ("out_for_delivery", "Out For Delivery"),
        ("delivered", "Delivered"),
        ("cancelled", "Cancelled"),
        ("returned", "Returned"),
        ("refund_initiated", "Refund Initiated"),
        ("refund_completed", "Refund Completed"),
    )

    order = models.ForeignKey(
        Order,
        on_delete=models.CASCADE,
        related_name="tracking_events",
    )

    status = models.CharField(
        max_length=50,
        choices=EVENT_STATUS_CHOICES,
    )

    title = models.CharField(max_length=255)

    description = models.TextField(blank=True, null=True)

    location = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    event_time = models.DateTimeField(default=timezone.now)

    is_customer_visible = models.BooleanField(default=True)

    metadata = models.JSONField(default=dict, blank=True)

    class Meta:
        db_table = "order_tracking_event"
        ordering = ["event_time"]

    def __str__(self):
        return f"{self.order.order_number} - {self.status}"
    
    
class Shipment(BaseModel):

    SHIPMENT_STATUS_CHOICES = (

        ("pending", "Pending"),

        ("ready_to_ship", "Ready To Ship"),

        ("shipped", "Shipped"),

        ("in_transit", "In Transit"),

        ("out_for_delivery", "Out For Delivery"),

        ("delivered", "Delivered"),

        ("failed", "Failed"),

        ("returned", "Returned"),
    )

    order = models.OneToOneField(
        Order,
        on_delete=models.CASCADE,
        related_name="shipment",
    )

    courier_name = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    tracking_number = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    awb_number = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    shipment_status = models.CharField(
        max_length=50,
        choices=SHIPMENT_STATUS_CHOICES,
        default="pending",
    )

    estimated_delivery_date = models.DateTimeField(
        blank=True,
        null=True,
    )

    shipped_at = models.DateTimeField(
        blank=True,
        null=True,
    )

    delivered_at = models.DateTimeField(
        blank=True,
        null=True,
    )

    metadata = models.JSONField(
        default=dict,
        blank=True,
    )

    class Meta:

        db_table = "shipment"

    def __str__(self):

        return f"{self.order.order_number} Shipment"
# =========================================================
# REVIEW / RETURN / SUPPORT / SERVICE MODELS
# =========================================================


class ProductReview(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="product_reviews"
    )
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="reviews"
    )
    rating = models.PositiveIntegerField()
    review_text = models.TextField(blank=True, null=True)
    is_verified_purchase = models.BooleanField(default=False)

    class Meta:
        db_table = "product_review"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.user.email} - {self.product.name}"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        self.update_product_review_summary()

    def delete(self, *args, **kwargs):
        product = self.product
        super().delete(*args, **kwargs)
        ProductReview.update_summary_for_product(product)

    def update_product_review_summary(self):
        ProductReview.update_summary_for_product(self.product)

    @staticmethod
    def update_summary_for_product(product):
        reviews = ProductReview.objects.filter(
            product=product, is_active=True, is_deleted=False
        )

        review_count = reviews.count()

        if review_count > 0:
            avg_rating = sum(review.rating for review in reviews) / review_count
        else:
            avg_rating = 0

        product.review_count = review_count
        product.rating_avg = round(avg_rating, 2)
        product.save(update_fields=["review_count", "rating_avg"])


class ProductReviewImage(BaseModel):
    review = models.ForeignKey(
        ProductReview, on_delete=models.CASCADE, related_name="review_images"
    )
    image = models.ImageField(upload_to="reviews/")

    class Meta:
        db_table = "product_review_image"
        ordering = ["-created_at"]

    def __str__(self):
        return f"Review Image - {self.review.id}"


class ReturnRequest(BaseModel):
    RETURN_STATUS_CHOICES = (
        ("requested", "Requested"),
        ("approved", "Approved"),
        ("rejected", "Rejected"),
        ("picked_up", "Picked Up"),
        ("refunded", "Refunded"),
        ("closed", "Closed"),
    )

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="return_requests"
    )
    order = models.ForeignKey(
        Order, on_delete=models.CASCADE, related_name="return_requests"
    )
    order_item = models.ForeignKey(
        OrderItem, on_delete=models.CASCADE, related_name="return_requests"
    )
    request_number = models.CharField(max_length=50, unique=True)
    reason = models.CharField(max_length=255)
    details = models.TextField(blank=True, null=True)
    status = models.CharField(
        max_length=30, choices=RETURN_STATUS_CHOICES, default="requested"
    )
    refund_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    requested_at = models.DateTimeField(blank=True, null=True)
    resolved_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        db_table = "return_request"
        ordering = ["-created_at"]

    def __str__(self):
        return self.request_number


class SupportTicket(BaseModel):
    TICKET_STATUS_CHOICES = (
        ("open", "Open"),
        ("in_progress", "In Progress"),
        ("resolved", "Resolved"),
        ("closed", "Closed"),
    )

    PRIORITY_CHOICES = (
        ("low", "Low"),
        ("medium", "Medium"),
        ("high", "High"),
    )

    CATEGORY_CHOICES = (
        ("order_issue", "Order Issue"),
        ("payment_issue", "Payment Issue"),
        ("refund_issue", "Refund Issue"),
        ("technical_support", "Technical Support"),
        ("other", "Other"),
    )

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="support_tickets"
    )
    ticket_number = models.CharField(max_length=50, unique=True)
    category = models.CharField(max_length=50, choices=CATEGORY_CHOICES)
    title = models.CharField(max_length=200)
    description = models.TextField()
    status = models.CharField(
        max_length=30, choices=TICKET_STATUS_CHOICES, default="open"
    )
    priority = models.CharField(
        max_length=20, choices=PRIORITY_CHOICES, default="medium"
    )

    class Meta:
        db_table = "support_ticket"
        ordering = ["-created_at"]

    def __str__(self):
        return self.ticket_number


class SupportTicketMessage(BaseModel):
    SENDER_TYPE_CHOICES = (
        ("user", "User"),
        ("admin", "Admin"),
    )

    ticket = models.ForeignKey(
        SupportTicket, on_delete=models.CASCADE, related_name="messages"
    )
    sender_type = models.CharField(
        max_length=20, choices=SENDER_TYPE_CHOICES, default="user"
    )
    message = models.TextField()
    attachment = models.FileField(upload_to="support/messages/", blank=True, null=True)

    class Meta:
        db_table = "support_ticket_message"
        ordering = ["created_at"]

    def __str__(self):
        return f"{self.ticket.ticket_number} - {self.sender_type}"


class ServiceRequest(BaseModel):
    SERVICE_STATUS_CHOICES = (
        ("requested", "Requested"),
        ("assigned", "Assigned"),
        ("in_progress", "In Progress"),
        ("completed", "Completed"),
        ("cancelled", "Cancelled"),
    )

    WARRANTY_STATUS_CHOICES = (
        ("in_warranty", "In Warranty"),
        ("out_of_warranty", "Out of Warranty"),
        ("unknown", "Unknown"),
    )

    DEVICE_TYPE_CHOICES = (
        ("laptop", "Laptop"),
        ("desktop", "Desktop"),
        ("printer", "Printer"),
        ("networking", "Networking"),
        ("display", "Display"),
        ("other", "Other"),
    )

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="service_requests"
    )
    request_number = models.CharField(max_length=50, unique=True)
    device_type = models.CharField(max_length=50, choices=DEVICE_TYPE_CHOICES)
    title = models.CharField(max_length=200)
    description = models.TextField()
    status = models.CharField(
        max_length=30, choices=SERVICE_STATUS_CHOICES, default="requested"
    )
    warranty_status = models.CharField(
        max_length=30, choices=WARRANTY_STATUS_CHOICES, default="unknown"
    )

    class Meta:
        db_table = "service_request"
        ordering = ["-created_at"]

    def __str__(self):
        return self.request_number


# =========================================================
# CMS / NOTIFICATION / SEARCH / RECENTLY VIEWED MODELS
# =========================================================


class CMSPage(BaseModel):
    PAGE_TYPE_CHOICES = (
        ("about_us", "About Us"),
        ("privacy_policy", "Privacy Policy"),
        ("terms_conditions", "Terms & Conditions"),
        ("refund_policy", "Refund Policy"),
        ("shipping_policy", "Shipping Policy"),
        ("contact_us", "Contact Us"),
        ("support_info", "Support Info"),
    )

    title = models.CharField(max_length=200)
    slug = models.SlugField(max_length=220, unique=True, blank=True, null=True)
    subtitle = models.CharField(max_length=255, blank=True, null=True)
    content = models.TextField()
    page_type = models.CharField(max_length=50, choices=PAGE_TYPE_CHOICES, unique=True)
    last_updated_label = models.CharField(max_length=120, blank=True, null=True)

    class Meta:
        db_table = "cms_page"
        ordering = ["title"]

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.title)
        super().save(*args, **kwargs)

    def __str__(self):
        return self.title


class Notification(BaseModel):
    NOTIFICATION_TYPE_CHOICES = (
        ("order", "Order"),
        ("payment", "Payment"),
        ("offer", "Offer"),
        ("support", "Support"),
        ("return", "Return"),
        ("service", "Service"),
        ("general", "General"),
    )

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="notifications"
    )
    title = models.CharField(max_length=200)
    message = models.TextField()
    notification_type = models.CharField(
        max_length=30, choices=NOTIFICATION_TYPE_CHOICES, default="general"
    )
    is_read = models.BooleanField(default=False)
    read_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        db_table = "notification"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.user.email} - {self.title}"


class RecentSearch(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="recent_searches"
    )
    keyword = models.CharField(max_length=255)

    class Meta:
        db_table = "recent_search"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.user.email} - {self.keyword}"


class RecentlyViewed(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="recently_viewed_products"
    )
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name="recent_views"
    )
    viewed_at = models.DateTimeField(default=timezone.now)

    class Meta:
        db_table = "recently_viewed"
        ordering = ["-viewed_at"]
        unique_together = ("user", "product")

    def __str__(self):
        return f"{self.user.email} - {self.product.name}"


class ReturnRequestImage(BaseModel):
    return_request = models.ForeignKey(
        ReturnRequest, on_delete=models.CASCADE, related_name="images"
    )
    image = models.ImageField(upload_to="returns/")


class ServiceRequestImage(BaseModel):
    service_request = models.ForeignKey(
        ServiceRequest, on_delete=models.CASCADE, related_name="images"
    )
    image = models.ImageField(upload_to="services/")


# ==========================cashback reward system api ==============================


# =========================================================
# REWARD / CASHBACK MODELS
# =========================================================


class CashbackRule(BaseModel):
    RULE_TYPE_CHOICES = (
        ("order_amount", "Order Amount"),
        ("cumulative_spend", "Cumulative Spend"),
    )

    CREDIT_ON_STATUS_CHOICES = (
        ("paid", "Paid"),
        ("delivered", "Delivered"),
    )

    title = models.CharField(max_length=200)
    description = models.TextField(blank=True, null=True)

    rule_type = models.CharField(max_length=30, choices=RULE_TYPE_CHOICES)
    threshold_amount = models.DecimalField(max_digits=12, decimal_places=2)
    reward_amount = models.DecimalField(max_digits=12, decimal_places=2)

    cumulative_days = models.PositiveIntegerField(default=0)
    credit_on_status = models.CharField(
        max_length=20, choices=CREDIT_ON_STATUS_CHOICES, default="delivered"
    )

    start_date = models.DateTimeField()
    end_date = models.DateTimeField()

    show_progress_hint = models.BooleanField(default=True)
    progress_message = models.CharField(max_length=255, blank=True, null=True)

    priority = models.PositiveIntegerField(default=0)

    class Meta:
        db_table = "cashback_rule"
        ordering = ["priority", "threshold_amount"]

    def __str__(self):
        return self.title

    def is_valid_now(self):
        now = timezone.now()
        return (
            self.is_active
            and not self.is_deleted
            and self.start_date <= now <= self.end_date
        )


class CashbackWallet(BaseModel):
    user = models.OneToOneField(
        User, on_delete=models.CASCADE, related_name="cashback_wallet"
    )
    available_balance = models.DecimalField(
        max_digits=12, decimal_places=2, default=0.00
    )
    locked_balance = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    total_earned = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    total_redeemed = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    total_expired = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)

    class Meta:
        db_table = "cashback_wallet"
        ordering = ["-created_at"]

    def __str__(self):
        return f"Wallet - {self.user.email}"


class CashbackTransaction(BaseModel):
    TRANSACTION_TYPE_CHOICES = (
        ("credit", "Credit"),
        ("debit", "Debit"),
        ("expire", "Expire"),
        ("reverse", "Reverse"),
    )

    SOURCE_TYPE_CHOICES = (
        ("order_reward", "Order Reward"),
        ("cumulative_reward", "Cumulative Reward"),
        ("wallet_redeem", "Wallet Redeem"),
        ("manual", "Manual"),
    )

    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="cashback_transactions"
    )
    wallet = models.ForeignKey(
        CashbackWallet, on_delete=models.CASCADE, related_name="transactions"
    )
    order = models.ForeignKey(
        Order,
        on_delete=models.SET_NULL,
        related_name="cashback_transactions",
        blank=True,
        null=True,
    )
    rule = models.ForeignKey(
        CashbackRule,
        on_delete=models.SET_NULL,
        related_name="cashback_transactions",
        blank=True,
        null=True,
    )

    transaction_type = models.CharField(max_length=20, choices=TRANSACTION_TYPE_CHOICES)
    source_type = models.CharField(max_length=30, choices=SOURCE_TYPE_CHOICES)

    amount = models.DecimalField(max_digits=12, decimal_places=2)
    balance_after_transaction = models.DecimalField(
        max_digits=12, decimal_places=2, default=0.00
    )

    remark = models.CharField(max_length=255, blank=True, null=True)
    expires_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        db_table = "cashback_transaction"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.user.email} - {self.transaction_type} - {self.amount}"


class CashbackRewardLog(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="cashback_reward_logs"
    )
    rule = models.ForeignKey(
        CashbackRule, on_delete=models.CASCADE, related_name="reward_logs"
    )
    order = models.ForeignKey(
        Order,
        on_delete=models.SET_NULL,
        related_name="cashback_reward_logs",
        blank=True,
        null=True,
    )
    reward_key = models.CharField(max_length=255, unique=True)
    credited_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0.00)
    credited_at = models.DateTimeField(default=timezone.now)

    class Meta:
        db_table = "cashback_reward_log"
        ordering = ["-created_at"]

    def __str__(self):
        return self.reward_key

    # =========================================================


# INVOICE / TALLY SYNC MODELS
# =========================================================


class InvoiceDocument(BaseModel):
    user = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name="invoice_documents"
    )
    order = models.OneToOneField(
        Order, on_delete=models.CASCADE, related_name="invoice_document"
    )
    invoice_number = models.CharField(max_length=60, unique=True)
    pdf_file = models.FileField(upload_to="invoices/")
    file_name = models.CharField(max_length=255, blank=True, null=True)
    email_sent = models.BooleanField(default=False)
    emailed_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        db_table = "invoice_document"
        ordering = ["-created_at"]

    def __str__(self):
        return self.invoice_number


class TallySyncLog(BaseModel):
    SYNC_TYPE_CHOICES = (
        ("order", "Order"),
        ("stock", "Stock"),
    )

    STATUS_CHOICES = (
        ("pending", "Pending"),
        ("success", "Success"),
        ("failed", "Failed"),
        ("retrying", "Retrying"),
    )

    user = models.ForeignKey(
        User,
        on_delete=models.SET_NULL,
        related_name="tally_sync_logs",
        blank=True,
        null=True,
    )
    order = models.ForeignKey(
        Order,
        on_delete=models.SET_NULL,
        related_name="tally_sync_logs",
        blank=True,
        null=True,
    )
    product = models.ForeignKey(
        Product,
        on_delete=models.SET_NULL,
        related_name="tally_sync_logs",
        blank=True,
        null=True,
    )

    sync_type = models.CharField(max_length=20, choices=SYNC_TYPE_CHOICES)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")

    request_payload = models.JSONField(default=dict, blank=True)
    response_payload = models.JSONField(default=dict, blank=True)

    retry_count = models.PositiveIntegerField(default=0)
    synced_at = models.DateTimeField(blank=True, null=True)
    error_message = models.TextField(blank=True, null=True)

    class Meta:
        db_table = "tally_sync_log"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.sync_type} - {self.status}"
    
    
    
    
    
    # =========================================================
# SAVED PAYMENT METHODS
# =========================================================

class SavedPaymentMethod(BaseModel):

    PAYMENT_TYPES = (
        ('upi', 'UPI'),
        ('card', 'Card'),
        ('bank', 'Bank'),
    )

    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='saved_payment_methods'
    )

    payment_type = models.CharField(
        max_length=20,
        choices=PAYMENT_TYPES
    )

    title = models.CharField(max_length=100)

    subtitle = models.CharField(max_length=200)

    provider = models.CharField(
        max_length=50,
        blank=True,
        null=True
    )

    token_reference = models.CharField(
        max_length=255,
        blank=True,
        null=True
    )

    is_default = models.BooleanField(default=False)

    class Meta:
        ordering = ['-is_default', '-created_at']

    def __str__(self):
        return f'{self.user.full_name} - {self.title}'



class DeliveryAgent(BaseModel):

    user = models.OneToOneField(

        User,

        on_delete=models.CASCADE,

        related_name="delivery_profile",
    )

    vehicle_number = models.CharField(

        max_length=100,

        blank=True,

        null=True,
    )

    is_available = models.BooleanField(
        default=True,
    )

    current_latitude = models.CharField(

        max_length=100,

        blank=True,

        null=True,
    )

    current_longitude = models.CharField(

        max_length=100,

        blank=True,

        null=True,
    )

    class Meta:

        db_table = "delivery_agent"

        ordering = ["-created_at"]

    def __str__(self):

        return self.user.full_name


# shipment structure
class Shipment(BaseModel):

    SHIPMENT_STATUS_CHOICES = (

        ("pending", "Pending"),

        ("ready_to_ship", "Ready To Ship"),

        ("shipped", "Shipped"),

        ("in_transit", "In Transit"),

        ("out_for_delivery", "Out For Delivery"),

        ("delivered", "Delivered"),

        ("failed", "Failed"),

        ("returned", "Returned"),
    )

    order = models.OneToOneField(
        Order,
        on_delete=models.CASCADE,
        related_name="shipment",
    )

    courier_name = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    tracking_number = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    awb_number = models.CharField(
        max_length=255,
        blank=True,
        null=True,
    )

    shipment_status = models.CharField(
        max_length=50,
        choices=SHIPMENT_STATUS_CHOICES,
        default="pending",
    )

    estimated_delivery_date = models.DateTimeField(
        blank=True,
        null=True,
    )

    shipped_at = models.DateTimeField(
        blank=True,
        null=True,
    )
    assigned_delivery_agent = models.ForeignKey(

    DeliveryAgent,

    on_delete=models.SET_NULL,

    blank=True,

    null=True,

    related_name="assigned_shipments",
)

    delivered_at = models.DateTimeField(
        blank=True,
        null=True,
    )

    metadata = models.JSONField(
        default=dict,
        blank=True,
    )

    class Meta:

        db_table = "shipment"

    def __str__(self):

        return f"{self.order.order_number} Shipment"



# Delivery Slot Model
