from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status, permissions
from rest_framework_simplejwt.views import TokenRefreshView
from django.core.paginator import Paginator
from django.db.models import Q, F, Avg, Count, Sum
from .models import *
from .serializers import *
import uuid
import logging
import razorpay
from django.conf import settings
from django.utils import timezone
from decimal import Decimal
from django.db import transaction

logger = logging.getLogger(__name__)


import os
from io import BytesIO
from decimal import Decimal
from datetime import timedelta
import requests
from django.conf import settings
from django.core.files.base import ContentFile
from django.core.mail import EmailMessage
from django.template.defaultfilters import slugify
from reportlab.lib.pagesizes import A4
from reportlab.pdfgen import canvas
from io import BytesIO
from reportlab.lib.units import mm
from reportlab.lib import colors
from MASTERAPP.services.order_tracking_service import create_tracking_event
from MASTERAPP.services.order_status_service import (
    handle_order_status_change,
)
from MASTERAPP.services.shipment_service import (
    update_shipment_status,
)

# =========================================================
# HEALTH CHECK API
# =========================================================


class HealthCheckAPIView(APIView):
    def get(self, request):
        return Response(
            {
                "success": True,
                "message": "NC-ECOM backend is running successfully.",
                "data": {},
            },
            status=status.HTTP_200_OK,
        )


def generate_invoice_number(order):
    return f"INV-{order.order_number}"


def build_invoice_file_name(order):
    return f"{generate_invoice_number(order)}.pdf"


def generate_order_invoice_pdf(order):
    buffer = BytesIO()
    p = canvas.Canvas(buffer, pagesize=A4)

    width, height = A4

    # =========================
    # THEME COLORS
    # =========================
    PRIMARY_GREEN = colors.HexColor("#16A34A")
    PRIMARY_ORANGE = colors.HexColor("#FF7A00")
    GREEN_SOFT = colors.HexColor("#E8F8EF")
    ORANGE_SOFT = colors.HexColor("#FFF3E8")
    GREY_TEXT = colors.HexColor("#424242")
    LIGHT_GREY = colors.HexColor("#E5E7EB")
    DARK_TEXT = colors.HexColor("#111111")
    WHITE = colors.white

    # =========================
    # HELPERS
    # =========================
    def money(val):
        try:
            return f"₹ {float(val):,.2f}"
        except:
            return f"₹ {val}"

    def safe_text(val):
        return str(val).strip() if val is not None else ""

    def draw_dual_border():
        # Outer green border
        p.setStrokeColor(PRIMARY_GREEN)
        p.setLineWidth(3)
        p.rect(8 * mm, 8 * mm, width - 16 * mm, height - 16 * mm, stroke=1, fill=0)

        # Inner orange border
        p.setStrokeColor(PRIMARY_ORANGE)
        p.setLineWidth(1.5)
        p.rect(12 * mm, 12 * mm, width - 24 * mm, height - 24 * mm, stroke=1, fill=0)

    def draw_header():
        # Header background blocks
        p.setFillColor(PRIMARY_GREEN)
        p.roundRect(
            16 * mm, height - 42 * mm, 110 * mm, 22 * mm, 4 * mm, stroke=0, fill=1
        )

        p.setFillColor(PRIMARY_ORANGE)
        p.roundRect(
            130 * mm, height - 42 * mm, 60 * mm, 22 * mm, 4 * mm, stroke=0, fill=1
        )

        # Company name
        p.setFillColor(WHITE)
        p.setFont("Helvetica-Bold", 20)
        p.drawString(22 * mm, height - 28 * mm, "NC-ECOM")

        p.setFont("Helvetica", 10)
        p.drawString(22 * mm, height - 35 * mm, "Narayani Computers")

        # Invoice label
        p.setFont("Helvetica-Bold", 16)
        p.drawCentredString(160 * mm, height - 29 * mm, "INVOICE")

    def draw_footer():
        p.setStrokeColor(LIGHT_GREY)
        p.setLineWidth(0.8)
        p.line(18 * mm, 22 * mm, width - 18 * mm, 22 * mm)

        p.setFillColor(GREY_TEXT)
        p.setFont("Helvetica", 8)
        p.drawString(20 * mm, 16 * mm, "Thank you for shopping with NC-ECOM.")
        p.drawRightString(
            width - 20 * mm, 16 * mm, "This is a system-generated invoice."
        )

    def draw_page_frame():
        draw_dual_border()
        draw_header()
        draw_footer()

    # =========================
    # PAGE START
    # =========================
    draw_page_frame()

    y = height - 55 * mm

    # =========================
    # INVOICE META BOX
    # =========================
    p.setFillColor(ORANGE_SOFT)
    p.setStrokeColor(PRIMARY_ORANGE)
    p.setLineWidth(1)
    p.roundRect(16 * mm, y - 2 * mm, 178 * mm, 20 * mm, 3 * mm, stroke=1, fill=1)

    p.setFillColor(DARK_TEXT)
    p.setFont("Helvetica-Bold", 10)
    p.drawString(
        20 * mm, y + 10 * mm, f"Invoice Number: {generate_invoice_number(order)}"
    )
    p.drawString(20 * mm, y + 4 * mm, f"Order Number: {safe_text(order.order_number)}")

    order_date = (
        order.placed_at.strftime("%d-%m-%Y %I:%M %p") if order.placed_at else ""
    )
    p.drawRightString(188 * mm, y + 10 * mm, f"Order Date: {order_date}")

    y -= 28 * mm

    # =========================
    # CUSTOMER SECTION
    # =========================
    p.setFillColor(PRIMARY_GREEN)
    p.roundRect(16 * mm, y, 178 * mm, 10 * mm, 2 * mm, stroke=0, fill=1)

    p.setFillColor(WHITE)
    p.setFont("Helvetica-Bold", 11)
    p.drawString(20 * mm, y + 3.2 * mm, "Billing / Shipping Details")

    y -= 18 * mm

    full_name = safe_text(order.address.full_name if order.address else "")
    phone = safe_text(order.address.phone if order.address else "")
    address_line_1 = safe_text(order.address.address_line_1 if order.address else "")
    address_line_2 = safe_text(order.address.address_line_2 if order.address else "")
    city = safe_text(order.address.city if order.address else "")
    state = safe_text(order.address.state if order.address else "")
    postal_code = safe_text(order.address.postal_code if order.address else "")
    country = safe_text(order.address.country if order.address else "")

    p.setFillColor(GREEN_SOFT)
    p.setStrokeColor(colors.HexColor("#D1FAE5"))
    p.roundRect(16 * mm, y - 14 * mm, 178 * mm, 28 * mm, 3 * mm, stroke=1, fill=1)

    p.setFillColor(DARK_TEXT)
    p.setFont("Helvetica-Bold", 10)
    p.drawString(20 * mm, y + 8 * mm, "Customer Name:")
    p.drawString(20 * mm, y + 2 * mm, "Phone:")
    p.drawString(20 * mm, y - 4 * mm, "Address:")
    p.drawString(20 * mm, y - 10 * mm, "Location:")

    p.setFont("Helvetica", 10)
    p.drawString(55 * mm, y + 8 * mm, full_name)
    p.drawString(55 * mm, y + 2 * mm, phone)
    p.drawString(55 * mm, y - 4 * mm, f"{address_line_1} {address_line_2}".strip())
    p.drawString(
        55 * mm, y - 10 * mm, f"{city}, {state} - {postal_code}, {country}".strip(" ,-")
    )

    y -= 38 * mm

    # =========================
    # ITEMS TITLE
    # =========================
    p.setFillColor(PRIMARY_ORANGE)
    p.roundRect(16 * mm, y, 178 * mm, 10 * mm, 2 * mm, stroke=0, fill=1)

    p.setFillColor(WHITE)
    p.setFont("Helvetica-Bold", 11)
    p.drawString(20 * mm, y + 3.2 * mm, "Order Items")

    y -= 14 * mm

    # =========================
    # TABLE HEADER
    # =========================
    table_x = 16 * mm
    table_width = 178 * mm
    row_height = 8 * mm

    col_product = table_x
    col_qty = 120 * mm
    col_rate = 140 * mm
    col_total = 167 * mm

    p.setFillColor(PRIMARY_GREEN)
    p.setStrokeColor(PRIMARY_GREEN)
    p.rect(table_x, y, table_width, row_height, stroke=0, fill=1)

    p.setFillColor(WHITE)
    p.setFont("Helvetica-Bold", 9)
    p.drawString(col_product + 3 * mm, y + 2.5 * mm, "Product")
    p.drawString(col_qty + 2 * mm, y + 2.5 * mm, "Qty")
    p.drawString(col_rate + 2 * mm, y + 2.5 * mm, "Rate")
    p.drawString(col_total + 2 * mm, y + 2.5 * mm, "Total")

    y -= row_height

    # =========================
    # ITEMS ROWS
    # =========================
    p.setFont("Helvetica", 9)
    items = order.order_items.all()

    for idx, item in enumerate(items):
        bg_color = colors.white if idx % 2 == 0 else colors.HexColor("#F9FAFB")
        p.setFillColor(bg_color)
        p.setStrokeColor(LIGHT_GREY)
        p.rect(table_x, y, table_width, row_height, stroke=1, fill=1)

        p.setFillColor(DARK_TEXT)
        p.drawString(
            col_product + 3 * mm, y + 2.5 * mm, safe_text(item.product_name)[:42]
        )
        p.drawString(col_qty + 4 * mm, y + 2.5 * mm, safe_text(item.quantity))
        p.drawRightString(col_rate + 22 * mm, y + 2.5 * mm, money(item.unit_price))
        p.drawRightString(col_total + 23 * mm, y + 2.5 * mm, money(item.total_price))

        y -= row_height

        if y < 65 * mm:
            p.showPage()
            draw_page_frame()
            y = height - 55 * mm

            # redraw section title after page break
            p.setFillColor(PRIMARY_ORANGE)
            p.roundRect(16 * mm, y, 178 * mm, 10 * mm, 2 * mm, stroke=0, fill=1)
            p.setFillColor(WHITE)
            p.setFont("Helvetica-Bold", 11)
            p.drawString(20 * mm, y + 3.2 * mm, "Order Items (Continued)")
            y -= 14 * mm

            p.setFillColor(PRIMARY_GREEN)
            p.rect(table_x, y, table_width, row_height, stroke=0, fill=1)
            p.setFillColor(WHITE)
            p.setFont("Helvetica-Bold", 9)
            p.drawString(col_product + 3 * mm, y + 2.5 * mm, "Product")
            p.drawString(col_qty + 2 * mm, y + 2.5 * mm, "Qty")
            p.drawString(col_rate + 2 * mm, y + 2.5 * mm, "Rate")
            p.drawString(col_total + 2 * mm, y + 2.5 * mm, "Total")
            y -= row_height
            p.setFont("Helvetica", 9)

    y -= 5 * mm

    # =========================
    # TOTALS BOX
    # =========================
    totals_box_x = 110 * mm
    totals_box_w = 84 * mm
    totals_box_h = 38 * mm

    p.setFillColor(ORANGE_SOFT)
    p.setStrokeColor(PRIMARY_ORANGE)
    p.setLineWidth(1)
    p.roundRect(
        totals_box_x,
        y - totals_box_h + 8 * mm,
        totals_box_w,
        totals_box_h,
        3 * mm,
        stroke=1,
        fill=1,
    )

    ty = y + 2 * mm

    p.setFillColor(DARK_TEXT)
    p.setFont("Helvetica", 10)
    p.drawString(totals_box_x + 5 * mm, ty, "Subtotal")
    p.drawRightString(totals_box_x + totals_box_w - 5 * mm, ty, money(order.subtotal))
    ty -= 6 * mm

    p.drawString(totals_box_x + 5 * mm, ty, "Discount")
    p.drawRightString(
        totals_box_x + totals_box_w - 5 * mm, ty, money(order.discount_amount)
    )
    ty -= 6 * mm

    p.drawString(totals_box_x + 5 * mm, ty, "Shipping")
    p.drawRightString(
        totals_box_x + totals_box_w - 5 * mm, ty, money(order.shipping_charge)
    )
    ty -= 6 * mm

    p.drawString(totals_box_x + 5 * mm, ty, "Tax")
    p.drawRightString(totals_box_x + totals_box_w - 5 * mm, ty, money(order.tax_amount))
    ty -= 8 * mm

    # Grand total highlight
    p.setFillColor(PRIMARY_GREEN)
    p.roundRect(
        totals_box_x + 3 * mm,
        ty - 2 * mm,
        totals_box_w - 6 * mm,
        9 * mm,
        2 * mm,
        stroke=0,
        fill=1,
    )

    p.setFillColor(WHITE)
    p.setFont("Helvetica-Bold", 11)
    p.drawString(totals_box_x + 7 * mm, ty + 1 * mm, "Grand Total")
    p.drawRightString(
        totals_box_x + totals_box_w - 8 * mm, ty + 1 * mm, money(order.total_amount)
    )

    # =========================
    # NOTE
    # =========================
    y = y - 42 * mm
    if y > 35 * mm:
        p.setFillColor(GREY_TEXT)
        p.setFont("Helvetica", 9)
        p.drawString(16 * mm, y, "We appreciate your business and trust in NC-ECOM.")

    p.showPage()
    p.save()

    pdf_value = buffer.getvalue()
    buffer.close()
    return pdf_value


def create_or_update_invoice_for_order(order):
    invoice_number = generate_invoice_number(order)
    file_name = build_invoice_file_name(order)
    pdf_bytes = generate_order_invoice_pdf(order)

    invoice, _ = InvoiceDocument.objects.get_or_create(
        order=order,
        defaults={
            "user": order.user,
            "invoice_number": invoice_number,
            "file_name": file_name,
        },
    )

    invoice.user = order.user
    invoice.invoice_number = invoice_number
    invoice.file_name = file_name
    invoice.pdf_file.save(file_name, ContentFile(pdf_bytes), save=False)
    invoice.save()

    return invoice


def send_invoice_email(invoice):

    user = invoice.order.user

    if not user or not user.email:
        raise Exception("User email not found")

    print("Sending email to:", user.email)

    subject = f"Your NC-ECOM Invoice - {invoice.invoice_number}"

    body = (
        f'Dear {user.full_name or "Customer"},\n\n'
        f"Thank you for your order.\n"
        f"Please find your invoice attached for order {invoice.order.order_number}.\n\n"
        f"Regards,\nNC-ECOM"
    )

    email = EmailMessage(
        subject=subject,
        body=body,
        from_email=settings.DEFAULT_FROM_EMAIL,
        to=[user.email],
    )

    # Attach PDF
    if invoice.pdf_file:
        if os.path.exists(invoice.pdf_file.path):
            email.attach_file(invoice.pdf_file.path)
            print("PDF attached:", invoice.pdf_file.path)
        else:
            raise Exception("PDF file not found")

    # Send email
    email.send(fail_silently=False)

    # Update invoice
    invoice.email_sent = True
    invoice.emailed_at = timezone.now()
    invoice.save(update_fields=["email_sent", "emailed_at"])

    print("Email sent successfully ✅")

    return True


# =========================================================
# TALLY SYNC HELPERS
# =========================================================


def build_tally_order_payload(order):
    return {
        "sync_type": "order",
        "order_number": order.order_number,
        "invoice_number": generate_invoice_number(order),
        "order_date": order.placed_at.isoformat() if order.placed_at else None,
        "payment_method": order.payment_method,
        "payment_status": order.payment_status,
        "order_status": order.status,
        "customer": {
            "name": order.address.full_name if order.address else "",
            "phone": order.address.phone if order.address else "",
            "email": order.user.email,
            "address_line_1": order.address.address_line_1 if order.address else "",
            "address_line_2": order.address.address_line_2 if order.address else "",
            "city": order.address.city if order.address else "",
            "state": order.address.state if order.address else "",
            "postal_code": order.address.postal_code if order.address else "",
            "country": order.address.country if order.address else "",
        },
        "totals": {
            "subtotal": str(order.subtotal),
            "discount_amount": str(order.discount_amount),
            "shipping_charge": str(order.shipping_charge),
            "tax_amount": str(order.tax_amount),
            "total_amount": str(order.total_amount),
        },
        "items": [
            {
                "product_id": item.product.id if item.product else None,
                "sku": item.product_sku,
                "name": item.product_name,
                "quantity": item.quantity,
                "unit_price": str(item.unit_price),
                "total_price": str(item.total_price),
            }
            for item in order.order_items.all()
        ],
    }


def create_tally_sync_log_for_order(order):

    logger.info(f"[TALLY] Creating log for Order ID: {order.id}")

    payload = build_tally_order_payload(order)

    logger.debug(f"[TALLY] Payload: {payload}")

    log = TallySyncLog.objects.create(
        user=order.user,
        order=order,
        sync_type="order",
        status="pending",
        request_payload=payload,
    )

    logger.info(f"[TALLY] Log created with ID: {log.id}")

    return log


def trigger_tally_sync_for_order(order):
    log = create_tally_sync_log_for_order(order)

    if not getattr(settings, "TALLY_SYNC_ENABLED", False):
        log.status = "failed"
        log.error_message = "Tally sync is disabled in settings."
        log.save(update_fields=["status", "error_message"])
        return log

    try:
        headers = {
            "Content-Type": "application/json",
        }

        token = getattr(settings, "TALLY_SYNC_TOKEN", "")
        if token:
            headers["Authorization"] = f"Bearer {token}"

        response = requests.post(
            settings.TALLY_SYNC_URL,
            json=log.request_payload,
            headers=headers,
            timeout=25,
        )

        response_data = {}
        try:
            response_data = response.json()
        except Exception:
            response_data = {"raw_response": response.text}

        if response.status_code in [200, 201] and response_data.get("success") == True:
            log.status = "success"
            log.response_payload = response_data
            log.synced_at = timezone.now()
            log.error_message = ""
            log.save(
                update_fields=[
                    "status",
                    "response_payload",
                    "synced_at",
                    "error_message",
                ]
            )
        else:
            log.status = "failed"
            log.response_payload = response_data
            log.error_message = (
                response_data.get("message") or f"HTTP {response.status_code}"
            )
            log.save(update_fields=["status", "response_payload", "error_message"])

    except requests.exceptions.ConnectionError as e:
        log.status = "failed"
        log.error_message = f"Bridge connection error: {str(e)}"
        log.save(update_fields=["status", "error_message"])
    except requests.exceptions.Timeout as e:
        log.status = "failed"
        log.error_message = f"Bridge timeout error: {str(e)}"
        log.save(update_fields=["status", "error_message"])
    except Exception as e:
        log.status = "failed"
        log.error_message = str(e)
        log.save(update_fields=["status", "error_message"])

    return log


# tally  bridge heath api


class TallyBridgeHealthAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        bridge_base_url = settings.TALLY_SYNC_URL.replace("/api/tally/sync-order/", "")
        ping_url = f"{bridge_base_url}/tally/ping"

        try:
            headers = {}
            token = getattr(settings, "TALLY_SYNC_TOKEN", "")
            if token:
                headers["Authorization"] = f"Bearer {token}"

            response = requests.get(
                ping_url,
                headers=headers,
                timeout=10,
            )

            data = {}
            try:
                data = response.json()
            except Exception:
                data = {"raw_response": response.text}

            return Response(
                {
                    "success": response.status_code == 200,
                    "message": "Bridge health checked successfully.",
                    "data": data,
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            return Response(
                {
                    "success": False,
                    "message": "Bridge health check failed.",
                    "errors": {"bridge": [str(e)]},
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


class TallyImportProductsAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        bridge_base_url = settings.TALLY_SYNC_URL.replace("/api/tally/sync-order/", "")
        export_url = f"{bridge_base_url}/api/tally/export-products/"

        try:
            headers = {}
            token = getattr(settings, "TALLY_SYNC_TOKEN", "")
            if token:
                headers["Authorization"] = f"Bearer {token}"

            response = requests.get(export_url, headers=headers, timeout=20)
            response_data = response.json()

            if response.status_code != 200 or response_data.get("success") != True:
                return Response(
                    {
                        "success": False,
                        "message": "Failed to import products from Tally bridge.",
                        "data": response_data,
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            imported = 0
            updated = 0

            for item in response_data.get("data", []):
                sku = item.get("sku")
                name = item.get("name", "")
                price = item.get("price", "0")
                stock_quantity = item.get("stock_quantity", 0)

                if not sku:
                    continue

                product = Product.objects.filter(sku=sku, is_deleted=False).first()

                if product:
                    product.name = name or product.name
                    product.price = price
                    product.stock_quantity = stock_quantity
                    product.save()
                    updated += 1
                else:
                    # IMPORTANT:
                    # New product create karne ke liye category/brand required hai.
                    # Isliye first phase me existing SKU update flow hi safest hai.
                    # Later category mapping add karenge.
                    continue

            return Response(
                {
                    "success": True,
                    "message": "Tally product import completed.",
                    "data": {
                        "updated": updated,
                        "imported": imported,
                    },
                },
                status=status.HTTP_200_OK,
            )

        except Exception as e:
            return Response(
                {
                    "success": False,
                    "message": "Failed to import products.",
                    "errors": {"tally_import": [str(e)]},
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


# def trigger_tally_stock_sync_for_product(product):
#     payload = {
#         "sku": product.sku,
#         "product_name": product.name,
#         "stock_quantity": product.stock_quantity,
#     }

#     log = TallySyncLog.objects.create(
#         product=product,
#         sync_type="stock",
#         status="pending",
#         request_payload=payload,
#     )

#     if not getattr(settings, "TALLY_SYNC_ENABLED", False):
#         log.status = "failed"
#         log.error_message = "Tally sync is disabled in settings."
#         log.save(update_fields=["status", "error_message"])
#         return log

#     try:
#         bridge_base_url = settings.TALLY_SYNC_URL.replace("/api/tally/sync-order/", "")
#         stock_sync_url = f"{bridge_base_url}/api/tally/sync-stock/"

#         headers = {"Content-Type": "application/json"}
#         token = getattr(settings, "TALLY_SYNC_TOKEN", "")
#         if token:
#             headers["Authorization"] = f"Bearer {token}"

#         response = requests.post(
#             stock_sync_url,
#             json=payload,
#             headers=headers,
#             timeout=20,
#         )

#         response_data = {}
#         try:
#             response_data = response.json()
#         except Exception:
#             response_data = {"raw_response": response.text}

#         if response.status_code in [200, 201] and response_data.get("success") == True:
#             log.status = "success"
#             log.response_payload = response_data
#             log.synced_at = timezone.now()
#             log.save(update_fields=["status", "response_payload", "synced_at"])
#         else:
#             log.status = "failed"
#             log.response_payload = response_data
#             log.error_message = (
#                 response_data.get("message") or f"HTTP {response.status_code}"
#             )
#             log.save(update_fields=["status", "response_payload", "error_message"])

#     except Exception as e:
#         log.status = "failed"
#         log.error_message = str(e)
#         log.save(update_fields=["status", "error_message"])

#     return log


# def trigger_tally_sync_for_order(order):

#     logger.info(f"[TALLY] Trigger started for Order ID: {order.id}")

#     log = create_tally_sync_log_for_order(order)

#     if not getattr(settings, 'TALLY_SYNC_ENABLED', False):
#         logger.warning("[TALLY] Sync disabled in settings")

#         log.status = 'failed'
#         log.error_message = 'Tally sync is disabled in settings.'
#         log.save(update_fields=['status', 'error_message'])

#         return log

#     try:
#         headers = {
#             'Content-Type': 'application/json',
#         }

#         token = getattr(settings, 'TALLY_SYNC_TOKEN', '')
#         if token:
#             headers['Authorization'] = f'Bearer {token}'

#         logger.info(f"[TALLY] Sending request to: {settings.TALLY_SYNC_URL}")
#         logger.debug(f"[TALLY] Headers: {headers}")

#         response = requests.post(
#             settings.TALLY_SYNC_URL,
#             json=log.request_payload,
#             headers=headers,
#             timeout=20,
#         )

#         logger.info(f"[TALLY] Response Status: {response.status_code}")

#         try:
#             response_data = response.json()
#         except Exception:
#             response_data = {'raw_response': response.text}

#         logger.debug(f"[TALLY] Response Data: {response_data}")

#         if response.status_code in [200, 201]:

#             logger.info(f"[TALLY] Sync SUCCESS for Order ID: {order.id}")

#             log.status = 'success'
#             log.response_payload = response_data
#             log.synced_at = timezone.now()

#             log.save(update_fields=['status', 'response_payload', 'synced_at'])

#         else:

#             logger.error(f"[TALLY] Sync FAILED with status {response.status_code}")

#             log.status = 'failed'
#             log.response_payload = response_data
#             log.error_message = f'HTTP {response.status_code}'

#             log.save(update_fields=['status', 'response_payload', 'error_message'])

#     except Exception as e:

#         logger.exception(f"[TALLY] Exception occurred: {str(e)}")

#         log.status = 'failed'
#         log.error_message = str(e)

#         log.save(update_fields=['status', 'error_message'])

#     return log


def get_or_create_cashback_wallet(user):
    wallet, _ = CashbackWallet.objects.get_or_create(user=user)
    return wallet


def create_app_notification(user, title, message, notification_type="general"):
    Notification.objects.create(
        user=user,
        title=title,
        message=message,
        notification_type=notification_type,
    )


def credit_cashback_to_wallet(
    user, amount, source_type, rule=None, order=None, remark=None, expires_at=None
):
    amount = Decimal(amount)
    wallet = get_or_create_cashback_wallet(user)

    wallet.available_balance += amount
    wallet.total_earned += amount
    wallet.save()

    txn = CashbackTransaction.objects.create(
        user=user,
        wallet=wallet,
        order=order,
        rule=rule,
        transaction_type="credit",
        source_type=source_type,
        amount=amount,
        balance_after_transaction=wallet.available_balance,
        remark=remark,
        expires_at=expires_at,
    )

    return txn


def get_active_cashback_rules():
    now = timezone.now()
    return CashbackRule.objects.filter(
        is_active=True, is_deleted=False, start_date__lte=now, end_date__gte=now
    ).order_by("priority", "threshold_amount")


def get_best_order_amount_rule_for_amount(amount):
    amount = Decimal(amount)
    rules = get_active_cashback_rules().filter(rule_type="order_amount")
    matched_rule = None

    for rule in rules:
        if amount >= rule.threshold_amount:
            matched_rule = rule

    return matched_rule


def get_next_order_amount_rule_for_amount(amount):
    amount = Decimal(amount)
    rules = get_active_cashback_rules().filter(rule_type="order_amount")
    for rule in rules:
        if amount < rule.threshold_amount:
            return rule
    return None


def get_cumulative_spend_for_days(user, days):
    start_time = timezone.now() - timedelta(days=days)

    total = Order.objects.filter(
        user=user,
        payment_status="paid",
        status__in=["confirmed", "processing", "shipped", "delivered"],
        placed_at__gte=start_time,
        is_active=True,
        is_deleted=False,
    ).aggregate(total=Sum("total_amount"))["total"] or Decimal("0.00")

    return Decimal(total)


def reward_key_for_order_rule(user, rule, order):
    return f"order_rule:{user.id}:{rule.id}:{order.id}"


def reward_key_for_cumulative_rule(user, rule, window_start, window_end):
    return (
        f"cumulative_rule:{user.id}:{rule.id}:{window_start.date()}:{window_end.date()}"
    )


def build_cashback_preview_for_amount(amount):
    amount = Decimal(amount)

    current_rule = get_best_order_amount_rule_for_amount(amount)
    next_rule = get_next_order_amount_rule_for_amount(amount)

    expected_cashback = current_rule.reward_amount if current_rule else Decimal("0.00")
    reward_hint = None

    if next_rule and next_rule.show_progress_hint:
        remaining = next_rule.threshold_amount - amount
        if remaining > 0:
            reward_hint = {
                "show": True,
                "message": next_rule.progress_message
                or (
                    f"Add products worth ₹{remaining} more to earn ₹{next_rule.reward_amount} cashback."
                ),
                "target_amount": next_rule.threshold_amount,
                "current_amount": amount,
                "remaining_amount": remaining,
                "reward_amount": next_rule.reward_amount,
            }

    return {
        "expected_cashback": expected_cashback,
        "matched_rule": (
            CashbackRuleSerializer(current_rule).data if current_rule else None
        ),
        "next_rule": CashbackRuleSerializer(next_rule).data if next_rule else None,
        "reward_hint": reward_hint,
    }


def process_cashback_for_order(order):
    credited_rewards = []
    rules = get_active_cashback_rules()

    # Order amount rules
    for rule in rules.filter(rule_type="order_amount"):
        should_credit = False

        if rule.credit_on_status == "paid" and order.payment_status == "paid":
            should_credit = True
        elif rule.credit_on_status == "delivered" and order.status == "delivered":
            should_credit = True

        if should_credit and Decimal(order.total_amount) >= rule.threshold_amount:
            reward_key = reward_key_for_order_rule(order.user, rule, order)

            if not CashbackRewardLog.objects.filter(reward_key=reward_key).exists():
                credit_cashback_to_wallet(
                    user=order.user,
                    amount=rule.reward_amount,
                    source_type="order_reward",
                    rule=rule,
                    order=order,
                    remark=f"Cashback earned on order {order.order_number}",
                )

                CashbackRewardLog.objects.create(
                    user=order.user,
                    rule=rule,
                    order=order,
                    reward_key=reward_key,
                    credited_amount=rule.reward_amount,
                )

                credited_rewards.append(
                    {
                        "rule_title": rule.title,
                        "amount": rule.reward_amount,
                        "type": "order_amount",
                    }
                )

                create_app_notification(
                    order.user,
                    "Cashback Earned",
                    f"You earned ₹{rule.reward_amount} cashback on order {order.order_number}.",
                    "order",
                )

    # Cumulative spend rules
    for rule in rules.filter(rule_type="cumulative_spend"):
        if rule.cumulative_days <= 0:
            continue

        should_credit = False

        if rule.credit_on_status == "paid" and order.payment_status == "paid":
            should_credit = True
        elif rule.credit_on_status == "delivered" and order.status == "delivered":
            should_credit = True

        if not should_credit:
            continue

        window_end = timezone.now()
        window_start = window_end - timedelta(days=rule.cumulative_days)
        total_spend = get_cumulative_spend_for_days(order.user, rule.cumulative_days)

        if total_spend >= rule.threshold_amount:
            reward_key = reward_key_for_cumulative_rule(
                order.user, rule, window_start, window_end
            )

            if not CashbackRewardLog.objects.filter(reward_key=reward_key).exists():
                credit_cashback_to_wallet(
                    user=order.user,
                    amount=rule.reward_amount,
                    source_type="cumulative_reward",
                    rule=rule,
                    order=order,
                    remark=f"Cumulative spend cashback earned in last {rule.cumulative_days} days.",
                )

                CashbackRewardLog.objects.create(
                    user=order.user,
                    rule=rule,
                    order=order,
                    reward_key=reward_key,
                    credited_amount=rule.reward_amount,
                )

                credited_rewards.append(
                    {
                        "rule_title": rule.title,
                        "amount": rule.reward_amount,
                        "type": "cumulative_spend",
                    }
                )

                create_app_notification(
                    order.user,
                    "Milestone Cashback Earned",
                    f"You earned ₹{rule.reward_amount} cashback for cumulative shopping milestone.",
                    "general",
                )

    return credited_rewards


# =========================================================
# AUTH APIs
# =========================================================


class RegisterAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = RegisterSerializer(data=request.data)

        if serializer.is_valid():
            user = serializer.save()

            return Response(
                {
                    "success": True,
                    "message": "Registration successful.",
                    "data": {
                        "user": UserProfileSerializer(user).data,
                    },
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class LoginAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = LoginSerializer(data=request.data)

        if serializer.is_valid():
            user = serializer.validated_data["user"]
            tokens = get_tokens_for_user(user)

            return Response(
                {
                    "success": True,
                    "message": "Login successful.",
                    "data": {
                        "user": UserProfileSerializer(user).data,
                        "tokens": tokens,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class ProfileAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        return Response(
            {
                "success": True,
                "message": "Profile fetched successfully.",
                "data": UserProfileSerializer(request.user).data,
            },
            status=status.HTTP_200_OK,
        )


# class ForgotPasswordAPIView(APIView):
#     permission_classes = [permissions.AllowAny]

#     def post(self, request):
#         serializer = ForgotPasswordSerializer(data=request.data)

#         if serializer.is_valid():
#             result = serializer.save()

#             return Response(
#                 {
#                     "success": True,
#                     "message": "OTP generated successfully for password reset.",
#                     "data": {
#                         "email": result["user"].email,
#                         "otp_preview_for_dev": result["otp_code"],
#                     },
#                 },
#                 status=status.HTTP_200_OK,
#             )

#         return Response(
#             {
#                 "success": False,
#                 "message": "Validation failed.",
#                 "errors": serializer.errors,
#             },
#             status=status.HTTP_400_BAD_REQUEST,
#         )

class ForgotPasswordAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = ForgotPasswordSerializer(data=request.data)

        if serializer.is_valid():
            result = serializer.save()

            return Response(
                {
                    "success": True,
                    "message": "OTP sent successfully to your email.",
                    "data": {
                        "email": result["user"].email,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )
class ResetPasswordAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = ResetPasswordSerializer(data=request.data)

        if serializer.is_valid():
            serializer.save()

            return Response(
                {"success": True, "message": "Password reset successful.", "data": {}},
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class CustomTokenRefreshAPIView(TokenRefreshView):
    permission_classes = [permissions.AllowAny]


# =========================================================
# CATEGORY / PRODUCT / HOME APIs
# =========================================================


class CategoryListAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        categories = Category.objects.filter(
            is_active=True, is_deleted=False, parent_category__isnull=True
        ).order_by("sort_order", "name")

        serializer = CategorySerializer(categories, many=True)

        return Response(
            {
                "success": True,
                "message": "Categories fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class ProductListAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        queryset = Product.objects.filter(
            is_active=True,
            is_deleted=False,
            category__is_active=True,
            category__is_deleted=False,
        ).select_related("category", "brand")

        category_slug = request.query_params.get("category_slug")
        brand_slug = request.query_params.get("brand_slug")
        search = request.query_params.get("search")
        sort = request.query_params.get("sort")
        min_price = request.query_params.get("min_price")
        max_price = request.query_params.get("max_price")
        in_stock = request.query_params.get("in_stock")
        featured_only = request.query_params.get("featured_only")
        best_selling_only = request.query_params.get("best_selling_only")
        latest_only = request.query_params.get("latest_only")
        discount_only = request.query_params.get("discount_only")

        if category_slug:
            queryset = queryset.filter(category__slug=category_slug)

        if brand_slug:
            queryset = queryset.filter(brand__slug=brand_slug)

        # if search:
        #     queryset = queryset.filter(
        #         Q(name__icontains=search) |
        #         Q(short_description__icontains=search) |
        #         Q(description__icontains=search) |
        #         Q(category__name__icontains=search) |
        #         Q(brand__name__icontains=search)
        #     )

        if search:
            queryset = queryset.filter(
                Q(name__icontains=search)
                | Q(short_description__icontains=search)
                | Q(description__icontains=search)
                | Q(category__name__icontains=search)
                | Q(brand__name__icontains=search)
                | Q(sku__icontains=search)
            )
        if min_price:
            queryset = queryset.filter(price__gte=min_price)

        if max_price:
            queryset = queryset.filter(price__lte=max_price)

        if in_stock == "true":
            queryset = queryset.filter(stock_quantity__gt=0)

        if featured_only == "true":
            queryset = queryset.filter(is_featured=True)

        if best_selling_only == "true":
            queryset = queryset.filter(is_best_selling=True)

        if latest_only == "true":
            queryset = queryset.order_by("-created_at")

        if discount_only == "true":
            queryset = queryset.filter(Q(old_price__gt=0) & Q(old_price__gt=F("price")))

        if sort == "price_low_to_high":
            queryset = queryset.order_by("price")
        elif sort == "price_high_to_low":
            queryset = queryset.order_by("-price")
        elif sort == "newest":
            queryset = queryset.order_by("-created_at")
        elif sort == "rating":
            queryset = queryset.order_by("-rating_avg")
        elif sort == "popularity":
            queryset = queryset.order_by("-review_count")
        else:
            queryset = queryset.order_by("-created_at")

        page = int(request.query_params.get("page", 1))
        page_size = int(request.query_params.get("page_size", 10))

        paginator = Paginator(queryset, page_size)
        page_obj = paginator.get_page(page)

        serializer = ProductListSerializer(page_obj.object_list, many=True)

        return Response(
            {
                "success": True,
                "message": "Products fetched successfully.",
                "data": {
                    "count": paginator.count,
                    "total_pages": paginator.num_pages,
                    "current_page": page_obj.number,
                    "next_page": (
                        page_obj.next_page_number() if page_obj.has_next() else None
                    ),
                    "previous_page": (
                        page_obj.previous_page_number()
                        if page_obj.has_previous()
                        else None
                    ),
                    "results": serializer.data,
                },
            },
            status=status.HTTP_200_OK,
        )


class ProductDetailAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, identifier):
        product = None

        if str(identifier).isdigit():
            product = (
                Product.objects.filter(
                    id=int(identifier), is_active=True, is_deleted=False
                )
                .select_related("category", "brand")
                .prefetch_related("product_images", "specifications", "highlights")
                .first()
            )
        else:
            product = (
                Product.objects.filter(
                    slug=identifier, is_active=True, is_deleted=False
                )
                .select_related("category", "brand")
                .prefetch_related("product_images", "specifications", "highlights")
                .first()
            )

        if not product:
            return Response(
                {"success": False, "message": "Product not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        related_products = (
            Product.objects.filter(
                category=product.category, is_active=True, is_deleted=False
            )
            .exclude(id=product.id)
            .select_related("category", "brand")[:8]
        )

        return Response(
            {
                "success": True,
                "message": "Product detail fetched successfully.",
                "data": {
                    "product": ProductDetailSerializer(product).data,
                    "related_products": ProductListSerializer(
                        related_products, many=True
                    ).data,
                },
            },
            status=status.HTTP_200_OK,
        )


class HomeAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        banners = Banner.objects.filter(
            is_active=True, is_deleted=False, show_on_home=True
        ).order_by("sort_order", "-created_at")[:10]

        categories = Category.objects.filter(
            is_active=True,
            is_deleted=False,
            show_on_home=True,
            parent_category__isnull=True,
        ).order_by("sort_order", "name")[:10]

        clients = Brand.objects.filter(is_active=True, is_deleted=False).order_by(
            "sort_order", "name"
        )[:10]

        latest_products = (
            Product.objects.filter(is_active=True, is_deleted=False)
            .select_related("category", "brand")
            .order_by("-created_at")[:10]
        )

        featured_products = (
            Product.objects.filter(is_active=True, is_deleted=False, is_featured=True)
            .select_related("category", "brand")
            .order_by("-created_at")[:10]
        )

        best_selling_products = (
            Product.objects.filter(
                is_active=True, is_deleted=False, is_best_selling=True
            )
            .select_related("category", "brand")
            .order_by("-created_at")[:10]
        )

        offer_products = (
            Product.objects.filter(
                Q(is_active=True)
                & Q(is_deleted=False)
                & Q(old_price__gt=0)
                & Q(old_price__gt=F("price"))
            )
            .select_related("category", "brand")
            .order_by("-created_at")[:10]
        )

        return Response(
            {
                "success": True,
                "message": "Home data fetched successfully.",
                "data": {
                    "banners": BannerSerializer(banners, many=True).data,
                    "categories": CategorySerializer(categories, many=True).data,
                    "latest_products": ProductListSerializer(
                        latest_products, many=True
                    ).data,
                    "featured_products": ProductListSerializer(
                        featured_products, many=True
                    ).data,
                    "best_selling_products": ProductListSerializer(
                        best_selling_products, many=True
                    ).data,
                    "offer_products": ProductListSerializer(
                        offer_products, many=True
                    ).data,
                    "clients": BrandSerializer(clients, many=True).data,
                },
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# WISHLIST APIs
# =========================================================


class WishlistToggleAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = WishlistToggleSerializer(data=request.data)

        if serializer.is_valid():
            product_id = serializer.validated_data["product_id"]
            product = Product.objects.get(
                id=product_id, is_active=True, is_deleted=False
            )

            wishlist_item = WishlistItem.objects.filter(
                user=request.user, product=product, is_deleted=False
            ).first()

            if wishlist_item:
                wishlist_item.delete()
                return Response(
                    {
                        "success": True,
                        "message": "Product removed from wishlist.",
                        "data": {"is_wishlisted": False},
                    },
                    status=status.HTTP_200_OK,
                )

            WishlistItem.objects.create(user=request.user, product=product)

            return Response(
                {
                    "success": True,
                    "message": "Product added to wishlist.",
                    "data": {"is_wishlisted": True},
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class WishlistListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        items = WishlistItem.objects.filter(
            user=request.user,
            is_active=True,
            is_deleted=False,
            product__is_active=True,
            product__is_deleted=False,
        ).select_related("product", "product__category", "product__brand")

        serializer = WishlistItemSerializer(items, many=True)

        return Response(
            {
                "success": True,
                "message": "Wishlist fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class CartAddAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = CartAddSerializer(data=request.data)

        if serializer.is_valid():
            product = serializer.validated_data["product"]
            quantity = serializer.validated_data["quantity"]

            cart, _ = Cart.objects.get_or_create(user=request.user)

            cart_item = CartItem.objects.filter(
                cart=cart, product=product, is_deleted=False
            ).first()

            if cart_item:
                new_quantity = cart_item.quantity + quantity

                if product.stock_quantity < new_quantity:
                    return Response(
                        {
                            "success": False,
                            "message": "Requested quantity exceeds stock.",
                            "data": {},
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                cart_item.quantity = new_quantity
                cart_item.price_at_time = product.price
                cart_item.save()
            else:
                CartItem.objects.create(
                    cart=cart,
                    product=product,
                    quantity=quantity,
                    price_at_time=product.price,
                )

            cart.refresh_from_db()
            cashback_preview = build_cashback_preview_for_amount(cart.subtotal)

            return Response(
                {
                    "success": True,
                    "message": "Cart updated successfully.",
                    "data": {
                        **CartSerializer(cart).data,
                        "cashback_preview": cashback_preview,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class CartDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        cart, _ = Cart.objects.get_or_create(user=request.user)

        cashback_preview = build_cashback_preview_for_amount(cart.subtotal)

        return Response(
            {
                "success": True,
                "message": "Cart fetched successfully.",
                "data": {
                    **CartSerializer(cart).data,
                    "cashback_preview": cashback_preview,
                },
            },
            status=status.HTTP_200_OK,
        )


# class CartDetailAPIView(APIView):
#     permission_classes = [permissions.IsAuthenticated]

#     def get(self, request):
#         cart, _ = Cart.objects.get_or_create(user=request.user)
#         cart_amount = Decimal(cart.subtotal)
#         current_rule = get_best_order_amount_rule_for_amount(cart_amount)
#         next_rule = get_next_order_amount_rule_for_amount(cart_amount)

#         reward_hint = None
#         expected_cashback = current_rule.reward_amount if current_rule else Decimal('0.00')

#         if next_rule and next_rule.show_progress_hint:
#             remaining = next_rule.threshold_amount - cart_amount
#             if remaining > 0:
#                 reward_hint = {
#                     'show': True,
#                     'message': next_rule.progress_message or f'Add products worth ₹{remaining} more to earn ₹{next_rule.reward_amount} cashback.',
#                     'target_amount': next_rule.threshold_amount,
#                     'current_amount': cart_amount,
#                     'remaining_amount': remaining,
#                     'reward_amount': next_rule.reward_amount,
#                 }

#         return Response(
#             {
#                 'success': True,
#                 'message': 'Cart fetched successfully.',
#                 'data': {
#                     'cart': CartSerializer(cart).data,
#                     'cashback_preview': {
#                     'reward_hint': reward_hint,
#                     'expected_cashback': expected_cashback
#                     },
#                 }
#             },
#             status=status.HTTP_200_OK
#         )


class CartItemUpdateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def patch(self, request, item_id):
        serializer = CartItemUpdateSerializer(data=request.data)

        if serializer.is_valid():
            try:
                cart = Cart.objects.get(user=request.user, is_deleted=False)
                cart_item = CartItem.objects.get(
                    id=item_id, cart=cart, is_deleted=False
                )
            except (Cart.DoesNotExist, CartItem.DoesNotExist):
                return Response(
                    {"success": False, "message": "Cart item not found.", "data": {}},
                    status=status.HTTP_404_NOT_FOUND,
                )

            quantity = serializer.validated_data["quantity"]

            if cart_item.product.stock_quantity < quantity:
                return Response(
                    {
                        "success": False,
                        "message": "Requested quantity exceeds stock.",
                        "data": {},
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            cart_item.quantity = quantity
            cart_item.price_at_time = cart_item.product.price
            cart_item.save()

            cart.refresh_from_db()

            return Response(
                {
                    "success": True,
                    "message": "Cart item updated successfully.",
                    "data": CartSerializer(cart).data,
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class CartItemDeleteAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request, item_id):
        try:
            cart = Cart.objects.get(user=request.user, is_deleted=False)
            cart_item = CartItem.objects.get(id=item_id, cart=cart, is_deleted=False)
        except (Cart.DoesNotExist, CartItem.DoesNotExist):
            return Response(
                {"success": False, "message": "Cart item not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        cart_item.delete()
        cart.refresh_from_db()

        return Response(
            {
                "success": True,
                "message": "Cart item removed successfully.",
                "data": CartSerializer(cart).data,
            },
            status=status.HTTP_200_OK,
        )


class CartClearAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request):
        try:
            cart = Cart.objects.get(user=request.user, is_deleted=False)
            cart.cart_items.all().delete()
        except Cart.DoesNotExist:
            cart = Cart.objects.create(user=request.user)

        cart.refresh_from_db()

        return Response(
            {
                "success": True,
                "message": "Cart cleared successfully.",
                "data": CartSerializer(cart).data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# ADDRESS APIs
# =========================================================


class AddressListCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        addresses = Address.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        )

        serializer = AddressSerializer(addresses, many=True)

        return Response(
            {
                "success": True,
                "message": "Addresses fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )

    def post(self, request):
        serializer = AddressSerializer(data=request.data, context={"request": request})

        if serializer.is_valid():
            address = serializer.save()

            return Response(
                {
                    "success": True,
                    "message": "Address added successfully.",
                    "data": AddressSerializer(address).data,
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class AddressDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get_object(self, request, address_id):
        return Address.objects.filter(
            id=address_id, user=request.user, is_deleted=False
        ).first()

    def get(self, request, address_id):
        address = self.get_object(request, address_id)

        if not address:
            return Response(
                {"success": False, "message": "Address not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "Address fetched successfully.",
                "data": AddressSerializer(address).data,
            },
            status=status.HTTP_200_OK,
        )

    def put(self, request, address_id):
        address = self.get_object(request, address_id)

        if not address:
            return Response(
                {"success": False, "message": "Address not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        serializer = AddressSerializer(
            address, data=request.data, context={"request": request}
        )

        if serializer.is_valid():
            address = serializer.save()

            return Response(
                {
                    "success": True,
                    "message": "Address updated successfully.",
                    "data": AddressSerializer(address).data,
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )

    def delete(self, request, address_id):
        address = self.get_object(request, address_id)

        if not address:
            return Response(
                {"success": False, "message": "Address not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        address.delete()

        return Response(
            {"success": True, "message": "Address deleted successfully.", "data": {}},
            status=status.HTTP_200_OK,
        )


class AddressSetDefaultAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, address_id):
        address = Address.objects.filter(
            id=address_id, user=request.user, is_deleted=False
        ).first()

        if not address:
            return Response(
                {"success": False, "message": "Address not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        Address.objects.filter(user=request.user, is_default=True).update(
            is_default=False
        )

        address.is_default = True
        address.save()

        return Response(
            {
                "success": True,
                "message": "Default address updated successfully.",
                "data": AddressSerializer(address).data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# COUPON / CHECKOUT / ORDER / PAYMENT APIs
# =========================================================


class CouponValidateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = CouponValidateSerializer(data=request.data)

        if serializer.is_valid():
            code = serializer.validated_data["code"].strip().upper()

            try:
                coupon = Coupon.objects.get(code=code, is_active=True, is_deleted=False)
            except Coupon.DoesNotExist:
                return Response(
                    {"success": False, "message": "Invalid coupon code.", "data": {}},
                    status=status.HTTP_404_NOT_FOUND,
                )

            if not coupon.is_valid_now():
                return Response(
                    {
                        "success": False,
                        "message": "Coupon is expired or inactive.",
                        "data": {},
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            cart, _ = Cart.objects.get_or_create(user=request.user)
            subtotal = Decimal(cart.subtotal)

            if subtotal < coupon.minimum_order_amount:
                return Response(
                    {
                        "success": False,
                        "message": f"Minimum order amount should be {coupon.minimum_order_amount}.",
                        "data": {},
                    },
                    status=status.HTTP_400_BAD_REQUEST,
                )

            discount_amount = Decimal("0.00")

            if coupon.discount_type == "percentage":
                discount_amount = (subtotal * coupon.discount_value) / Decimal("100")
                if (
                    coupon.maximum_discount_amount > 0
                    and discount_amount > coupon.maximum_discount_amount
                ):
                    discount_amount = coupon.maximum_discount_amount
            else:
                discount_amount = coupon.discount_value

            return Response(
                {
                    "success": True,
                    "message": "Coupon validated successfully.",
                    "data": {
                        "coupon_id": coupon.id,
                        "code": coupon.code,
                        "title": coupon.title,
                        "discount_amount": discount_amount,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class ReviewDeleteAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request, review_id):
        review = ProductReview.objects.filter(id=review_id, user=request.user).first()

        if not review:
            return Response(
                {"success": False, "message": "Review not found"}, status=404
            )

        review.delete()

        return Response({"success": True, "message": "Review deleted"})


class CheckoutReviewAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = CheckoutReviewSerializer(data=request.data)

        if serializer.is_valid():
            address_id = serializer.validated_data["address_id"]
            coupon_code = (
                serializer.validated_data.get("coupon_code", "").strip().upper()
            )
            payment_method = serializer.validated_data["payment_method"]
            # ==================================================
            # ONLINE PAYMENT MUST USE VERIFY FLOW
            # ==================================================

            if payment_method == "razorpay":

                return Response(
                    {
                        "success": False,
                        "message": (
                            "Use create-razorpay-order API " "for online payments."
                        ),
                    },
                    status=400,
                )

            cart, _ = Cart.objects.get_or_create(user=request.user)

            cart_items = (
                cart.cart_items.select_for_update()
                .filter(
                    is_active=True,
                    is_deleted=False,
                    product__is_active=True,
                    product__is_deleted=False,
                )
                .select_related("product")
            )

            if not cart_items.exists():
                return Response(
                    {"success": False, "message": "Cart is empty.", "data": {}},
                    status=status.HTTP_400_BAD_REQUEST,
                )

            address = Address.objects.filter(
                id=address_id, user=request.user, is_active=True, is_deleted=False
            ).first()

            if not address:
                return Response(
                    {"success": False, "message": "Address not found.", "data": {}},
                    status=status.HTTP_404_NOT_FOUND,
                )

            subtotal = Decimal("0.00")

            for item in cart_items:
                if item.product.stock_quantity < item.quantity:
                    return Response(
                        {
                            "success": False,
                            "message": f"Insufficient stock for {item.product.name}.",
                            "data": {},
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                subtotal += Decimal(item.product.price) * item.quantity

            discount_amount = Decimal("0.00")
            coupon = None

            if coupon_code:
                coupon = Coupon.objects.filter(
                    code=coupon_code, is_active=True, is_deleted=False
                ).first()

                if not coupon:
                    return Response(
                        {
                            "success": False,
                            "message": "Invalid coupon code.",
                            "data": {},
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                if not coupon.is_valid_now():
                    return Response(
                        {
                            "success": False,
                            "message": "Coupon is expired or inactive.",
                            "data": {},
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                if subtotal < coupon.minimum_order_amount:
                    return Response(
                        {
                            "success": False,
                            "message": f"Minimum order amount should be {coupon.minimum_order_amount}.",
                            "data": {},
                        },
                        status=status.HTTP_400_BAD_REQUEST,
                    )

                if coupon.discount_type == "percentage":
                    discount_amount = (subtotal * coupon.discount_value) / Decimal(
                        "100"
                    )
                    if (
                        coupon.maximum_discount_amount > 0
                        and discount_amount > coupon.maximum_discount_amount
                    ):
                        discount_amount = coupon.maximum_discount_amount
                else:
                    discount_amount = coupon.discount_value

            shipping_charge = Decimal("0.00")
            tax_amount = Decimal("0.00")
            total_amount = subtotal - discount_amount + shipping_charge + tax_amount

            cashback_preview = build_cashback_preview_for_amount(total_amount)

            return Response(
                {
                    "success": True,
                    "message": "Checkout review generated successfully.",
                    "data": {
                        "address": AddressSerializer(address).data,
                        "payment_method": payment_method,
                        "coupon_code": coupon.code if coupon else None,
                        "subtotal": subtotal,
                        "discount_amount": discount_amount,
                        "shipping_charge": shipping_charge,
                        "tax_amount": tax_amount,
                        "total_amount": total_amount,
                        "cart": CartSerializer(cart).data,
                        "cashback_preview": cashback_preview,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class CreateRazorpayOrderAPIView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):

        serializer = RazorpayOrderCreateSerializer(data=request.data)

        if not serializer.is_valid():

            return Response(
                {
                    "success": False,
                    "message": "Validation failed.",
                    "errors": serializer.errors,
                },
                status=400,
            )

        address_id = serializer.validated_data["address_id"]

        coupon_code = (
            serializer.validated_data.get(
                "coupon_code",
                "",
            )
            .strip()
            .upper()
        )

        cart, _ = Cart.objects.get_or_create(user=request.user)

        cart_items = cart.cart_items.filter(
            is_active=True,
            is_deleted=False,
        ).select_related("product")

        if not cart_items.exists():

            return Response(
                {
                    "success": False,
                    "message": "Cart is empty.",
                },
                status=400,
            )

        address = Address.objects.filter(
            id=address_id,
            user=request.user,
            is_active=True,
            is_deleted=False,
        ).first()

        if not address:

            return Response(
                {
                    "success": False,
                    "message": "Address not found.",
                },
                status=404,
            )

        subtotal = Decimal("0.00")

        for item in cart_items:

            if item.product.stock_quantity < item.quantity:

                return Response(
                    {
                        "success": False,
                        "message": f"Insufficient stock for {item.product.name}",
                    },
                    status=400,
                )

            subtotal += Decimal(item.product.price) * item.quantity

        discount_amount = Decimal("0.00")

        if coupon_code:

            coupon = Coupon.objects.filter(
                code=coupon_code,
                is_active=True,
                is_deleted=False,
            ).first()

            if coupon and coupon.is_valid_now():

                if subtotal >= coupon.minimum_order_amount:

                    if coupon.discount_type == "percentage":

                        discount_amount = (subtotal * coupon.discount_value) / Decimal(
                            "100"
                        )

                        if (
                            coupon.maximum_discount_amount > 0
                            and discount_amount > coupon.maximum_discount_amount
                        ):
                            discount_amount = coupon.maximum_discount_amount

                    else:

                        discount_amount = coupon.discount_value

        shipping_charge = Decimal("0.00")

        tax_amount = Decimal("0.00")

        total_amount = subtotal - discount_amount + shipping_charge + tax_amount

        client = razorpay.Client(
            auth=(
                settings.RAZORPAY_KEY_ID,
                settings.RAZORPAY_KEY_SECRET,
            )
        )

        razorpay_order = client.order.create(
            {
                "amount": int(total_amount * 100),
                "currency": "INR",
                "payment_capture": 1,
            }
        )

        return Response(
            {
                "success": True,
                "message": "Razorpay order created.",
                "data": {
                    "razorpay_order_id": razorpay_order["id"],
                    "amount": razorpay_order["amount"],
                    "currency": "INR",
                    "key": settings.RAZORPAY_KEY_ID,
                },
            },
            status=200,
        )


class VerifyPaymentAPIView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    @transaction.atomic
    def post(self, request):

        serializer = VerifyPaymentSerializer(data=request.data)

        if not serializer.is_valid():

            return Response(
                {
                    "success": False,
                    "message": "Validation failed.",
                    "errors": serializer.errors,
                },
                status=400,
            )

        data = serializer.validated_data

        address_id = data["address_id"]

        coupon_code = data.get("coupon_code", "").strip().upper()

        gateway_order_id = data["gateway_order_id"]

        gateway_payment_id = data["gateway_payment_id"]

        gateway_signature = data["gateway_signature"]

        # ==================================================
        # PREVENT DUPLICATE PAYMENT
        # ==================================================

        existing_transaction = (
            PaymentTransaction.objects.filter(
                gateway_payment_id=gateway_payment_id,
                status="paid",
                is_deleted=False,
            )
            .select_related("order")
            .first()
        )

        if existing_transaction:

            return Response(
                {
                    "success": True,
                    "message": "Payment already processed.",
                    "data": OrderListSerializer(existing_transaction.order).data,
                },
                status=200,
            )

        # ==================================================
        # VERIFY SIGNATURE
        # ==================================================

        client = razorpay.Client(
            auth=(
                settings.RAZORPAY_KEY_ID,
                settings.RAZORPAY_KEY_SECRET,
            )
        )

        try:

            client.utility.verify_payment_signature(
                {
                    "razorpay_order_id": gateway_order_id,
                    "razorpay_payment_id": gateway_payment_id,
                    "razorpay_signature": gateway_signature,
                }
            )

        except Exception:

            return Response(
                {
                    "success": False,
                    "message": "Invalid payment signature.",
                },
                status=400,
            )

        # ==================================================
        # GET CART
        # ==================================================

        cart, _ = Cart.objects.get_or_create(user=request.user)

        cart_items = cart.cart_items.filter(
            is_active=True,
            is_deleted=False,
        ).select_related("product")

        if not cart_items.exists():

            return Response(
                {
                    "success": False,
                    "message": "Cart is empty.",
                },
                status=400,
            )

        # ==================================================
        # ADDRESS
        # ==================================================

        address = Address.objects.filter(
            id=address_id,
            user=request.user,
            is_active=True,
            is_deleted=False,
        ).first()

        if not address:

            return Response(
                {
                    "success": False,
                    "message": "Address not found.",
                },
                status=404,
            )

        # ==================================================
        # CALCULATE TOTALS
        # ==================================================

        subtotal = Decimal("0.00")

        for item in cart_items:

            product = Product.objects.select_for_update().get(id=item.product.id)
            # STOCK RECHECK
            if product.stock_quantity < item.quantity:

                return Response(
                    {
                        "success": False,
                        "message": f"{product.name} is out of stock.",
                    },
                    status=400,
                )

            subtotal += Decimal(product.price) * item.quantity

        discount_amount = Decimal("0.00")

        coupon = None

        if coupon_code:

            coupon = Coupon.objects.filter(
                code=coupon_code,
                is_active=True,
                is_deleted=False,
            ).first()

            if coupon and coupon.is_valid_now():

                if subtotal >= coupon.minimum_order_amount:

                    if coupon.discount_type == "percentage":

                        discount_amount = (subtotal * coupon.discount_value) / Decimal(
                            "100"
                        )

                        if (
                            coupon.maximum_discount_amount > 0
                            and discount_amount > coupon.maximum_discount_amount
                        ):
                            discount_amount = coupon.maximum_discount_amount

                    else:

                        discount_amount = coupon.discount_value

        shipping_charge = Decimal("0.00")

        tax_amount = Decimal("0.00")

        total_amount = subtotal - discount_amount + shipping_charge + tax_amount

        # ==================================================
        # CREATE ORDER
        # ==================================================

        order = Order.objects.create(
            user=request.user,
            address=address,
            order_number=f"NCORD-{uuid.uuid4().hex[:10].upper()}",
            status="confirmed",
            subtotal=subtotal,
            discount_amount=discount_amount,
            shipping_charge=shipping_charge,
            tax_amount=tax_amount,
            total_amount=total_amount,
            payment_method="razorpay",
            payment_status="paid",
            coupon=coupon,
            placed_at=timezone.now(),
        )
            # ==================================================
            # INITIAL TRACKING EVENTS
            # ==================================================
        Shipment.objects.create(
                order=order,
            )
        create_tracking_event(
                order=order,
                status="placed",
                title="Order Placed",
                description="Your order has been placed successfully.",
            )

        create_tracking_event(
                order=order,
                status="confirmed",
                title="Payment Successful",
                description="Your payment has been verified successfully.",
            )
        
        
        # ==================================================
        # CREATE ORDER ITEMS
        # ==================================================

        for item in cart_items:

            product = item.product

            OrderItem.objects.create(
                order=order,
                product=product,
                product_name=product.name,
                product_sku=product.sku,
                quantity=item.quantity,
                unit_price=product.price,
                total_price=(Decimal(product.price) * item.quantity),
            )

            # STOCK REDUCE
            product.stock_quantity -= item.quantity

            product.save()

        # ==================================================
        # PAYMENT TRANSACTION
        # ==================================================

        PaymentTransaction.objects.create(
            order=order,
            user=request.user,
            amount=total_amount,
            payment_gateway="razorpay",
            status="paid",
            gateway_order_id=gateway_order_id,
            gateway_payment_id=gateway_payment_id,
            gateway_signature=gateway_signature,
            paid_at=timezone.now(),
        )

        # ==================================================
        # CLEAR CART
        # ==================================================

        cart.cart_items.all().delete()

        # ==================================================
        # INVOICE
        # ==================================================

        try:

            invoice = create_or_update_invoice_for_order(order)

            try:
                send_invoice_email(invoice)

            except Exception as e:

                logger.exception(f"Invoice email failed: {str(e)}")

        except Exception as e:

            logger.exception(f"Invoice generation failed: {str(e)}")

        # ==================================================
        # CASHBACK
        # ==================================================

        try:

            process_cashback_for_order(order)

        except Exception as e:

            logger.exception(f"Cashback failed: {str(e)}")

        # ==================================================
        # TALLY
        # ==================================================

        # try:

        #     trigger_tally_sync_for_order(order)

        # except Exception as e:

        #     logger.exception(f"Tally sync failed: {str(e)}")

        create_app_notification(
            request.user,
            "Payment Successful",
            f"Your order {order.order_number} has been placed successfully.",
            "order",
        )
        # ==================================================
        # SUCCESS RESPONSE
        # ==================================================

        return Response(
            {
                "success": True,
                "message": "Payment verified successfully.",
                "data": {
                    "order": OrderDetailSerializer(
                        order,
                        context={"request": request},
                    ).data,
                    "cashback_preview": build_cashback_preview_for_amount(total_amount),
                },
            },
            status=200,
        )


class PlaceOrderAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = CheckoutReviewSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(
                {
                    "success": False,
                    "message": "Validation failed.",
                    "errors": serializer.errors,
                },
                status=status.HTTP_400_BAD_REQUEST,
            )

        address_id = serializer.validated_data["address_id"]
        coupon_code = serializer.validated_data.get("coupon_code", "").strip().upper()
        payment_method = serializer.validated_data["payment_method"]
        
        # ==========================================
# BLOCK ONLINE PAYMENT
# ==========================================

        if payment_method == "razorpay":

            return Response(
                {
                    "success": False,
                    "message":
                        "Use Razorpay payment API.",
                },
                status=400,
            )

        cart, _ = Cart.objects.get_or_create(user=request.user)

        cart_items = cart.cart_items.filter(
            is_active=True,
            is_deleted=False,
            product__is_active=True,
            product__is_deleted=False,
        ).select_related("product")

        if not cart_items.exists():
            return Response({"success": False, "message": "Cart is empty."}, status=400)

        address = Address.objects.filter(
            id=address_id, user=request.user, is_active=True, is_deleted=False
        ).first()

        if not address:
            return Response(
                {"success": False, "message": "Address not found."}, status=404
            )

        # ================= CALCULATIONS =================
        subtotal = Decimal("0.00")

        for item in cart_items:
            if item.product.stock_quantity < item.quantity:
                return Response(
                    {
                        "success": False,
                        "message": f"Insufficient stock for {item.product.name}.",
                    },
                    status=400,
                )

            subtotal += Decimal(item.product.price) * item.quantity

        discount_amount = Decimal("0.00")
        coupon = None

        if coupon_code:
            coupon = Coupon.objects.filter(
                code=coupon_code, is_active=True, is_deleted=False
            ).first()

            if (
                coupon
                and coupon.is_valid_now()
                and subtotal >= coupon.minimum_order_amount
            ):
                if coupon.discount_type == "percentage":
                    discount_amount = (subtotal * coupon.discount_value) / Decimal(
                        "100"
                    )
                    if (
                        coupon.maximum_discount_amount > 0
                        and discount_amount > coupon.maximum_discount_amount
                    ):
                        discount_amount = coupon.maximum_discount_amount
                else:
                    discount_amount = coupon.discount_value

        shipping_charge = Decimal("0.00")
        tax_amount = Decimal("0.00")
        total_amount = subtotal - discount_amount + shipping_charge + tax_amount

        order_number = f"NCORD-{uuid.uuid4().hex[:10].upper()}"

        # ================= ORDER =================
        order = Order.objects.create(
            user=request.user,
            order_number=order_number,
            address=address,
            status="pending",
            subtotal=subtotal,
            discount_amount=discount_amount,
            shipping_charge=shipping_charge,
            tax_amount=tax_amount,
            total_amount=total_amount,
            payment_method=payment_method,
            payment_status="pending",
            coupon=coupon,
            placed_at=timezone.now(),
        )
        
        create_tracking_event(
                order=order,
                status="placed",
                title="Order Placed",
                description="Your order has been placed successfully.",
            )

        # ================= ORDER ITEMS =================
        for item in cart_items:
            OrderItem.objects.create(
                order=order,
                product=item.product,
                product_name=item.product.name,
                product_sku=item.product.sku,
                quantity=item.quantity,
                unit_price=item.product.price,
                total_price=Decimal(item.product.price) * item.quantity,
            )

        # ================= COD DIRECT CONFIRM =================
        if payment_method == "cod":

            order.status = "confirmed"
            order.payment_status = "pending"
            
            order.save()
            create_tracking_event(
                order=order,
                status="confirmed",
                title="Order Confirmed",
                description="Your COD order has been confirmed.",
            )

            # ================= STOCK =================
            for item in cart_items:

                product = item.product

                product.stock_quantity -= item.quantity

                product.save()

            # ================= CLEAR CART =================
            cart.cart_items.all().delete()

        # ================= INVOICE =================
        invoice = None
        try:
            if payment_method == "cod":
                invoice = create_or_update_invoice_for_order(order)

                try:
                    send_invoice_email(invoice)
                except Exception:
                    pass
        except Exception:
            pass

        # ================= TALLY =================
        # try:
        #     if payment_method == "cod":
        #         trigger_tally_sync_for_order(order)
        # except Exception:
        #     pass

        # ================= NOTIFICATION =================
        create_app_notification(
            request.user,
            "Order Placed",
            f"Your order {order.order_number} has been placed successfully.",
            "order",
        )

        # ================= CASHBACK =================
        cashback_preview = build_cashback_preview_for_amount(total_amount)

        # ================= RESPONSE =================
        # ================= RESPONSE =================
        return Response(
            {
                "success": True,
                "message": "Order placed successfully.",
                "data": {
                    "order": OrderDetailSerializer(
                        order,
                        context={"request": request},
                    ).data,
                    "invoice": (
                        InvoiceDocumentSerializer(
                            invoice,
                            context={"request": request},
                        ).data
                        if invoice
                        else None
                    ),
                    "cashback_preview": cashback_preview,
                    "cashback_note": (
                        f"You may earn ₹"
                        f"{cashback_preview['expected_cashback']} cashback"
                        if cashback_preview.get("expected_cashback")
                        else None
                    ),
                },
            },
            status=status.HTTP_201_CREATED,
        )


class OrderListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        orders = Order.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        ).order_by("-created_at")

        page = int(request.query_params.get("page", 1))
        page_size = int(request.query_params.get("page_size", 10))

        paginator = Paginator(orders, page_size)
        page_obj = paginator.get_page(page)

        serializer = OrderListSerializer(page_obj.object_list, many=True)

        return Response(
            {
                "success": True,
                "message": "Orders fetched successfully.",
                "data": {
                    "count": paginator.count,
                    "total_pages": paginator.num_pages,
                    "current_page": page_obj.number,
                    "next_page": (
                        page_obj.next_page_number() if page_obj.has_next() else None
                    ),
                    "previous_page": (
                        page_obj.previous_page_number()
                        if page_obj.has_previous()
                        else None
                    ),
                    "results": serializer.data,
                },
            },
            status=status.HTTP_200_OK,
        )


class OrderDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, order_id):
        order = (
            Order.objects.filter(
                id=order_id, user=request.user, is_active=True, is_deleted=False
            )
            .prefetch_related("order_items")
            .select_related("address", "coupon")
            .first()
        )

        if not order:
            return Response(
                {"success": False, "message": "Order not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "Order detail fetched successfully.",
                "data": OrderDetailSerializer(order).data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# REVIEW APIs
# =========================================================


class ProductReviewListAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, product_id):
        product = Product.objects.filter(
            id=product_id, is_active=True, is_deleted=False
        ).first()

        if not product:
            return Response(
                {"success": False, "message": "Product not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        reviews = (
            ProductReview.objects.filter(
                product=product, is_active=True, is_deleted=False
            )
            .select_related("user")
            .prefetch_related("review_images")
        )

        serializer = ProductReviewSerializer(reviews, many=True)

        rating_summary = reviews.aggregate(
            average_rating=Avg("rating"), total_reviews=Count("id")
        )

        return Response(
            {
                "success": True,
                "message": "Reviews fetched successfully.",
                "data": {
                    "summary": {
                        "average_rating": rating_summary["average_rating"] or 0,
                        "total_reviews": rating_summary["total_reviews"] or 0,
                    },
                    "results": serializer.data,
                },
            },
            status=status.HTTP_200_OK,
        )


class ReviewCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = ReviewCreateSerializer(data=request.data)

        if serializer.is_valid():
            product_id = serializer.validated_data["product_id"]
            rating = serializer.validated_data["rating"]
            review_text = serializer.validated_data.get("review_text", "")

            product = Product.objects.get(
                id=product_id, is_active=True, is_deleted=False
            )

            is_verified_purchase = OrderItem.objects.filter(
                order__user=request.user, order__payment_status="paid", product=product
            ).exists()

            review = ProductReview.objects.create(
                user=request.user,
                product=product,
                rating=rating,
                review_text=review_text,
                is_verified_purchase=is_verified_purchase,
            )

            return Response(
                {
                    "success": True,
                    "message": "Review submitted successfully.",
                    "data": ProductReviewSerializer(review).data,
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class MyReviewListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        reviews = (
            ProductReview.objects.filter(
                user=request.user, is_active=True, is_deleted=False
            )
            .select_related("product")
            .prefetch_related("review_images")
        )

        serializer = ProductReviewSerializer(reviews, many=True)

        return Response(
            {
                "success": True,
                "message": "My reviews fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# RETURN APIs
# =========================================================


class ReturnRequestCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = ReturnRequestCreateSerializer(
            data=request.data, context={"request": request}
        )

        if serializer.is_valid():
            order = serializer.validated_data["order"]
            order_item = serializer.validated_data["order_item"]
            reason = serializer.validated_data["reason"]
            details = serializer.validated_data.get("details", "")

            request_number = f"RET-{uuid.uuid4().hex[:10].upper()}"
            refund_amount = order_item.total_price

            return_request = ReturnRequest.objects.create(
                user=request.user,
                order=order,
                order_item=order_item,
                request_number=request_number,
                reason=reason,
                details=details,
                status="requested",
                refund_amount=refund_amount,
                requested_at=timezone.now(),
            )

            return Response(
                {
                    "success": True,
                    "message": "Return request created successfully.",
                    "data": ReturnRequestSerializer(return_request).data,
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class ReturnRequestListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        items = ReturnRequest.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        ).select_related("order", "order_item")

        serializer = ReturnRequestSerializer(items, many=True)

        return Response(
            {
                "success": True,
                "message": "Return requests fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class ReturnRequestDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, request_id):
        item = (
            ReturnRequest.objects.filter(
                id=request_id, user=request.user, is_active=True, is_deleted=False
            )
            .select_related("order", "order_item")
            .first()
        )

        if not item:
            return Response(
                {"success": False, "message": "Return request not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "Return request fetched successfully.",
                "data": ReturnRequestSerializer(item).data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# SUPPORT TICKET APIs
# =========================================================


class SupportTicketCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = SupportTicketCreateSerializer(data=request.data)

        if serializer.is_valid():
            ticket = SupportTicket.objects.create(
                user=request.user,
                ticket_number=f"SUP-{uuid.uuid4().hex[:10].upper()}",
                category=serializer.validated_data["category"],
                title=serializer.validated_data["title"],
                description=serializer.validated_data["description"],
                priority=serializer.validated_data["priority"],
                status="open",
            )

            SupportTicketMessage.objects.create(
                ticket=ticket,
                sender_type="user",
                message=serializer.validated_data["description"],
            )

            return Response(
                {
                    "success": True,
                    "message": "Support ticket created successfully.",
                    "data": SupportTicketSerializer(ticket).data,
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class SupportTicketListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        tickets = SupportTicket.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        ).prefetch_related("messages")

        serializer = SupportTicketSerializer(tickets, many=True)

        return Response(
            {
                "success": True,
                "message": "Support tickets fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class SupportTicketDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, ticket_id):
        ticket = (
            SupportTicket.objects.filter(
                id=ticket_id, user=request.user, is_active=True, is_deleted=False
            )
            .prefetch_related("messages")
            .first()
        )

        if not ticket:
            return Response(
                {"success": False, "message": "Support ticket not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "Support ticket detail fetched successfully.",
                "data": SupportTicketSerializer(ticket).data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# SERVICE REQUEST APIs
# =========================================================


class ServiceRequestCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = ServiceRequestCreateSerializer(data=request.data)

        if serializer.is_valid():
            item = ServiceRequest.objects.create(
                user=request.user,
                request_number=f"SRV-{uuid.uuid4().hex[:10].upper()}",
                device_type=serializer.validated_data["device_type"],
                title=serializer.validated_data["title"],
                description=serializer.validated_data["description"],
                warranty_status=serializer.validated_data["warranty_status"],
                status="requested",
            )

            return Response(
                {
                    "success": True,
                    "message": "Service request created successfully.",
                    "data": ServiceRequestSerializer(item).data,
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class ServiceRequestListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        items = ServiceRequest.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        )

        serializer = ServiceRequestSerializer(items, many=True)

        return Response(
            {
                "success": True,
                "message": "Service requests fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class ServiceRequestDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, request_id):
        item = ServiceRequest.objects.filter(
            id=request_id, user=request.user, is_active=True, is_deleted=False
        ).first()

        if not item:
            return Response(
                {"success": False, "message": "Service request not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "Service request detail fetched successfully.",
                "data": ServiceRequestSerializer(item).data,
            },
            status=status.HTTP_200_OK,
        )


class ServiceRequestListCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        queryset = ServiceRequest.objects.filter(user=request.user, is_deleted=False)

        serializer = ServiceRequestSerializer(queryset, many=True)

        return Response(
            {
                "success": True,
                "message": "Service requests fetched successfully.",
                "data": serializer.data,
            }
        )

    def post(self, request):
        serializer = ServiceRequestCreateSerializer(data=request.data)

        if serializer.is_valid():
            obj = ServiceRequest.objects.create(
                user=request.user,
                request_number=f"SRV-{uuid.uuid4().hex[:8].upper()}",
                device_type=serializer.validated_data["device_type"],
                title=serializer.validated_data["title"],
                description=serializer.validated_data["description"],
                warranty_status=serializer.validated_data["warranty_status"],
            )

            return Response(
                {
                    "success": True,
                    "message": "Service request created successfully.",
                    "data": ServiceRequestSerializer(obj).data,
                }
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=400,
        )


# =========================================================
# CMS APIs
# =========================================================


class CMSPageListAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        pages = CMSPage.objects.filter(is_active=True, is_deleted=False).order_by(
            "title"
        )

        serializer = CMSPageSerializer(pages, many=True)

        return Response(
            {
                "success": True,
                "message": "CMS pages fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class CMSPageDetailAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, slug):
        page = CMSPage.objects.filter(
            slug=slug, is_active=True, is_deleted=False
        ).first()

        if not page:
            return Response(
                {"success": False, "message": "CMS page not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "CMS page fetched successfully.",
                "data": CMSPageSerializer(page).data,
            },
            status=status.HTTP_200_OK,
        )


class CMSPageByTypeAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request, page_type):
        page = CMSPage.objects.filter(
            page_type=page_type, is_active=True, is_deleted=False
        ).first()

        if not page:
            return Response(
                {"success": False, "message": "CMS page not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        return Response(
            {
                "success": True,
                "message": "CMS page fetched successfully.",
                "data": CMSPageSerializer(page).data,
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# NOTIFICATION APIs
# =========================================================


class NotificationListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        items = Notification.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        ).order_by("-created_at")

        page = int(request.query_params.get("page", 1))
        page_size = int(request.query_params.get("page_size", 10))

        paginator = Paginator(items, page_size)
        page_obj = paginator.get_page(page)

        serializer = NotificationSerializer(page_obj.object_list, many=True)

        unread_count = Notification.objects.filter(
            user=request.user, is_read=False, is_active=True, is_deleted=False
        ).count()

        return Response(
            {
                "success": True,
                "message": "Notifications fetched successfully.",
                "data": {
                    "unread_count": unread_count,
                    "count": paginator.count,
                    "total_pages": paginator.num_pages,
                    "current_page": page_obj.number,
                    "next_page": (
                        page_obj.next_page_number() if page_obj.has_next() else None
                    ),
                    "previous_page": (
                        page_obj.previous_page_number()
                        if page_obj.has_previous()
                        else None
                    ),
                    "results": serializer.data,
                },
            },
            status=status.HTTP_200_OK,
        )


class NotificationMarkReadAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, notification_id):
        item = Notification.objects.filter(
            id=notification_id, user=request.user, is_active=True, is_deleted=False
        ).first()

        if not item:
            return Response(
                {"success": False, "message": "Notification not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        item.is_read = True
        item.read_at = timezone.now()
        item.save()

        return Response(
            {
                "success": True,
                "message": "Notification marked as read.",
                "data": NotificationSerializer(item).data,
            },
            status=status.HTTP_200_OK,
        )


class NotificationMarkAllReadAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        Notification.objects.filter(
            user=request.user, is_read=False, is_active=True, is_deleted=False
        ).update(is_read=True, read_at=timezone.now())

        return Response(
            {
                "success": True,
                "message": "All notifications marked as read.",
                "data": {},
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# RECENT SEARCH APIs
# =========================================================


class RecentSearchListCreateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        items = RecentSearch.objects.filter(
            user=request.user, is_active=True, is_deleted=False
        ).order_by("-created_at")[:10]

        serializer = RecentSearchSerializer(items, many=True)

        return Response(
            {
                "success": True,
                "message": "Recent searches fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )

    def post(self, request):
        serializer = RecentSearchCreateSerializer(data=request.data)

        if serializer.is_valid():
            keyword = serializer.validated_data["keyword"]

            existing = RecentSearch.objects.filter(
                user=request.user, keyword__iexact=keyword, is_deleted=False
            ).first()

            if existing:
                existing.created_at = timezone.now()
                existing.save(update_fields=["created_at"])
                item = existing
            else:
                item = RecentSearch.objects.create(user=request.user, keyword=keyword)

            return Response(
                {
                    "success": True,
                    "message": "Recent search saved successfully.",
                    "data": RecentSearchSerializer(item).data,
                },
                status=status.HTTP_201_CREATED,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class RecentSearchDeleteAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request, search_id):
        item = RecentSearch.objects.filter(
            id=search_id, user=request.user, is_deleted=False
        ).first()

        if not item:
            return Response(
                {"success": False, "message": "Recent search not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        item.delete()

        return Response(
            {
                "success": True,
                "message": "Recent search deleted successfully.",
                "data": {},
            },
            status=status.HTTP_200_OK,
        )


class RecentSearchClearAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def delete(self, request):
        RecentSearch.objects.filter(user=request.user, is_deleted=False).delete()

        return Response(
            {
                "success": True,
                "message": "Recent searches cleared successfully.",
                "data": {},
            },
            status=status.HTTP_200_OK,
        )


# =========================================================
# RECENTLY VIEWED APIs
# =========================================================


class RecentlyViewedTrackAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = RecentlyViewedTrackSerializer(data=request.data)

        if serializer.is_valid():
            product_id = serializer.validated_data["product_id"]
            product = Product.objects.get(
                id=product_id, is_active=True, is_deleted=False
            )

            item, created = RecentlyViewed.objects.get_or_create(
                user=request.user,
                product=product,
                defaults={"viewed_at": timezone.now()},
            )

            if not created:
                item.viewed_at = timezone.now()
                item.save(update_fields=["viewed_at"])

            return Response(
                {
                    "success": True,
                    "message": "Recently viewed item tracked successfully.",
                    "data": RecentlyViewedSerializer(item).data,
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class RecentlyViewedListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        items = (
            RecentlyViewed.objects.filter(
                user=request.user,
                is_active=True,
                is_deleted=False,
                product__is_active=True,
                product__is_deleted=False,
            )
            .select_related("product", "product__category", "product__brand")
            .order_by("-viewed_at")[:20]
        )

        serializer = RecentlyViewedSerializer(items, many=True)

        return Response(
            {
                "success": True,
                "message": "Recently viewed products fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class ReviewImageUploadAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = ReviewImageUploadSerializer(data=request.data)

        if serializer.is_valid():
            review_id = serializer.validated_data["review_id"]
            images = serializer.validated_data["images"]

            review = ProductReview.objects.filter(
                id=review_id, user=request.user
            ).first()

            if not review:
                return Response(
                    {"success": False, "message": "Review not found"}, status=404
                )

            created_images = []

            for img in images:
                obj = ProductReviewImage.objects.create(review=review, image=img)
                created_images.append(obj.image.url)

            return Response(
                {"success": True, "message": "Images uploaded", "data": created_images}
            )

        return Response({"errors": serializer.errors}, status=400)


class SupportTicketReplyAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, ticket_id):
        message = request.data.get("message")

        ticket = SupportTicket.objects.filter(id=ticket_id, user=request.user).first()

        if not ticket:
            return Response({"message": "Ticket not found"}, status=404)

        msg = SupportTicketMessage.objects.create(
            ticket=ticket, sender_type="user", message=message
        )

        return Response(
            {"success": True, "data": SupportTicketMessageSerializer(msg).data}
        )


class ReturnImageUploadAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, request_id):
        images = request.FILES.getlist("images")

        rr = ReturnRequest.objects.filter(id=request_id, user=request.user).first()

        if not rr:
            return Response({"message": "Return request not found"}, status=404)

        for img in images:
            ReturnRequestImage.objects.create(return_request=rr, image=img)

        return Response({"success": True, "message": "Uploaded"})


class ServiceImageUploadAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, request_id):
        images = request.FILES.getlist("images")

        sr = ServiceRequest.objects.filter(id=request_id, user=request.user).first()

        if not sr:
            return Response({"message": "Not found"}, status=404)

        for img in images:
            ServiceRequestImage.objects.create(service_request=sr, image=img)

        return Response({"success": True})


class CancelOrderAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, order_id):
        order = Order.objects.filter(id=order_id, user=request.user).first()

        if not order:
            return Response({"message": "Order not found"}, status=404)

        if order.status not in ["pending", "confirmed"]:
            return Response({"message": "Cannot cancel"}, status=400)

        order.status = "cancelled"
        order.cancelled_at = timezone.now()
        order.save()

        return Response({"success": True, "message": "Order cancelled"})


class ProfileUpdateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def put(self, request):
        serializer = ProfileUpdateSerializer(
            request.user, data=request.data, partial=True
        )

        if serializer.is_valid():
            serializer.save()

            return Response({"success": True, "data": serializer.data})

        return Response(serializer.errors, status=400)


# notification auto system helper function
def create_notification(user, title, message, n_type="general"):
    Notification.objects.create(
        user=user, title=title, message=message, notification_type=n_type
    )


# class DashboardAPIView(APIView):
#     permission_classes = [permissions.IsAuthenticated]

#     def get(self, request):
#         user = request.user

#         orders = Order.objects.filter(user=user)
#         cart = Cart.objects.filter(user=user).first()
#         wishlist = WishlistItem.objects.filter(user=user)

#         return Response({
#             'success': True,
#             'data': {
#                 'total_orders': orders.count(),
#                 'pending_orders': orders.filter(status='pending').count(),
#                 'cart_items': cart.cart_items.count() if cart else 0,
#                 'wishlist_items': wishlist.count(),
#             }
#         })


class DashboardAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        user = request.user

        orders = Order.objects.filter(user=user, is_deleted=False)
        cart = Cart.objects.filter(user=user, is_deleted=False).first()
        wishlist = WishlistItem.objects.filter(user=user, is_deleted=False)
        wallet = get_or_create_cashback_wallet(user)

        return Response(
            {
                "success": True,
                "message": "Dashboard fetched successfully.",
                "data": {
                    "total_orders": orders.count(),
                    "pending_orders": orders.filter(status="pending").count(),
                    "confirmed_orders": orders.filter(status="confirmed").count(),
                    "delivered_orders": orders.filter(status="delivered").count(),
                    "cart_items": (
                        cart.cart_items.filter(is_deleted=False).count() if cart else 0
                    ),
                    "wishlist_items": wishlist.count(),
                    "cashback_wallet": CashbackWalletSerializer(wallet).data,
                },
            }
        )

class SavedPaymentMethodApiView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    # =====================================================
    # GET ALL PAYMENT METHODS
    # =====================================================

    def get(self, request, payment_id=None):

        if payment_id:
            payment_methods = SavedPaymentMethod.objects.filter(
                id=payment_id,
                user=request.user,
                is_deleted=False
            )
        else:
            payment_methods = SavedPaymentMethod.objects.filter(
                user=request.user,
                is_deleted=False
            ).order_by('-is_default', '-created_at')

        serializer = SavedPaymentMethodSerializer(
            payment_methods,
            many=True,
            context={'request': request}
        )

        return Response({
            'success': True,
            'message': 'Saved payment methods fetched successfully.',
            'data': serializer.data
        })

    # =====================================================
    # CREATE PAYMENT METHOD
    # =====================================================

    def post(self, request):

        serializer = SavedPaymentMethodSerializer(
            data=request.data,
            context={'request': request}
        )

        if serializer.is_valid():

            payment_method = serializer.save()

            return Response({
                'success': True,
                'message': 'Payment method saved successfully.',
                'data': SavedPaymentMethodSerializer(
                    payment_method,
                    context={'request': request}
                ).data
            }, status=status.HTTP_201_CREATED)

        return Response({
            'success': False,
            'message': 'Validation failed.',
            'errors': serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)
    
    def patch(self, request, payment_id):
            payment_method = SavedPaymentMethod.objects.filter(
                id=payment_id,
                user=request.user,
                is_deleted=False,
            ).first()

            if not payment_method:
                return Response(
                    {
                        "success": False,
                        "message": "Payment method not found.",
                    },
                    status=status.HTTP_404_NOT_FOUND,
                )

            SavedPaymentMethod.objects.filter(
                user=request.user,
                is_deleted=False,
            ).update(is_default=False)

            payment_method.is_default = True
            payment_method.save(update_fields=["is_default"])

            return Response(
                {
                    "success": True,
                    "message": "Default payment method updated.",
                }
            )

    # =====================================================
    # UPDATE PAYMENT METHOD
    # =====================================================
    
    
    # =====================================================
    # DELETE PAYMENT METHOD
    # =====================================================
    def delete(self, request, payment_id):

        payment_method = SavedPaymentMethod.objects.filter(
            id=payment_id,
            user=request.user,
            is_deleted=False
        ).first()

        # Check if payment method exists
        if not payment_method:
            return Response({
                'success': False,
                'message': 'Payment method not found.',
                'data': {}
            }, status=status.HTTP_404_NOT_FOUND)

        # Soft delete
        payment_method.is_deleted = True
        payment_method.save()

        return Response({
            'success': True,
            'message': 'Payment method deleted successfully.',
            'data': {}
        }, status=status.HTTP_200_OK)
        

    def put(self, request, payment_id):

        payment_method = SavedPaymentMethod.objects.filter(
            id=payment_id,
            user=request.user,
            is_deleted=False
        ).first()

        if not payment_method:

            return Response({
                'success': False,
                'message': 'Payment method not found.',
                'data': {}
            }, status=status.HTTP_404_NOT_FOUND)

        serializer = SavedPaymentMethodSerializer(
            payment_method,
            data=request.data,
            partial=True,
            context={'request': request}
        )

        if serializer.is_valid():

            serializer.save()

            return Response({
                'success': True,
                'message': 'Payment method updated successfully.',
                'data': serializer.data
            })

        return Response({
            'success': False,
            'message': 'Validation failed.',
            'errors': serializer.errors
        }, status=status.HTTP_400_BAD_REQUEST)



class SetDefaultPaymentMethodAPIView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, payment_id):

        payment_method = SavedPaymentMethod.objects.filter(
            id=payment_id,
            user=request.user,
            is_deleted=False
        ).first()

        if not payment_method:

            return Response({
                'success': False,
                'message': 'Payment method not found.',
                'data': {}
            }, status=status.HTTP_404_NOT_FOUND)

        SavedPaymentMethod.objects.filter(
            user=request.user,
            is_default=True
        ).update(is_default=False)

        payment_method.is_default = True
        payment_method.save(update_fields=['is_default'])

        return Response({
            'success': True,
            'message': 'Default payment method updated successfully.',
            'data': SavedPaymentMethodSerializer(
                payment_method,
                context={'request': request}
            ).data
        })
        
        
        
        

    # =====================================================
    # DELETE PAYMENT METHOD
    # =====================================================

    def delete(self, request, payment_id):

        payment_method = SavedPaymentMethod.objects.filter(
            id=payment_id,
            user=request.user,
            is_deleted=False
        ).first()

        if not payment_method:

            return Response({
                'success': False,
                'message': 'Payment method not found.',
                'data': {}
            }, status=status.HTTP_404_NOT_FOUND)

        was_default = payment_method.is_default

        payment_method.is_deleted = True
        payment_method.save(update_fields=['is_deleted'])

        # AUTO ASSIGN NEXT DEFAULT
        if was_default:

            next_method = SavedPaymentMethod.objects.filter(
                user=request.user,
                is_deleted=False
            ).exclude(id=payment_method.id).first()

            if next_method:
                next_method.is_default = True
                next_method.save(update_fields=['is_default'])

        return Response({
            'success': True,
            'message': 'Payment method deleted successfully.',
            'data': {}
        })
        
# =========================================================
# CASHBACK / REWARD APIs
# =========================================================


class CashbackWalletAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        wallet = get_or_create_cashback_wallet(request.user)

        return Response(
            {
                "success": True,
                "message": "Cashback wallet fetched successfully.",
                "data": CashbackWalletSerializer(wallet).data,
            },
            status=status.HTTP_200_OK,
        )


class CashbackTransactionListAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):
        wallet = get_or_create_cashback_wallet(request.user)
        items = wallet.transactions.filter(is_active=True, is_deleted=False).order_by(
            "-created_at"
        )

        page = int(request.query_params.get("page", 1))
        page_size = int(request.query_params.get("page_size", 10))

        paginator = Paginator(items, page_size)
        page_obj = paginator.get_page(page)

        serializer = CashbackTransactionSerializer(page_obj.object_list, many=True)

        return Response(
            {
                "success": True,
                "message": "Cashback transactions fetched successfully.",
                "data": {
                    "count": paginator.count,
                    "total_pages": paginator.num_pages,
                    "current_page": page_obj.number,
                    "next_page": (
                        page_obj.next_page_number() if page_obj.has_next() else None
                    ),
                    "previous_page": (
                        page_obj.previous_page_number()
                        if page_obj.has_previous()
                        else None
                    ),
                    "results": serializer.data,
                },
            },
            status=status.HTTP_200_OK,
        )


class CashbackRulesAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def get(self, request):
        rules = get_active_cashback_rules()
        serializer = CashbackRuleSerializer(rules, many=True)

        return Response(
            {
                "success": True,
                "message": "Cashback rules fetched successfully.",
                "data": serializer.data,
            },
            status=status.HTTP_200_OK,
        )


class CashbackPreviewAPIView(APIView):
    permission_classes = [permissions.AllowAny]

    def post(self, request):
        serializer = CashbackPreviewSerializer(data=request.data)

        if serializer.is_valid():
            cart_amount = Decimal(serializer.validated_data["cart_amount"])

            current_rule = get_best_order_amount_rule_for_amount(cart_amount)
            next_rule = get_next_order_amount_rule_for_amount(cart_amount)

            expected_cashback = (
                current_rule.reward_amount if current_rule else Decimal("0.00")
            )

            progress_hint = None
            if next_rule and next_rule.show_progress_hint:
                remaining = next_rule.threshold_amount - cart_amount
                if remaining > 0:
                    progress_hint = {
                        "show": True,
                        "message": next_rule.progress_message
                        or (
                            f"Add products worth ₹{remaining} more to earn ₹{next_rule.reward_amount} cashback."
                        ),
                        "target_amount": next_rule.threshold_amount,
                        "current_amount": cart_amount,
                        "remaining_amount": remaining,
                        "reward_amount": next_rule.reward_amount,
                    }

            return Response(
                {
                    "success": True,
                    "message": "Cashback preview fetched successfully.",
                    "data": {
                        "cart_amount": cart_amount,
                        "expected_cashback": expected_cashback,
                        "matched_rule": (
                            CashbackRuleSerializer(current_rule).data
                            if current_rule
                            else None
                        ),
                        "next_rule": (
                            CashbackRuleSerializer(next_rule).data
                            if next_rule
                            else None
                        ),
                        "progress_hint": progress_hint,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class CashbackOrderRewardTriggerAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = CashbackOrderTriggerSerializer(data=request.data)

        if serializer.is_valid():
            order_id = serializer.validated_data["order_id"]

            order = Order.objects.filter(
                id=order_id, user=request.user, is_active=True, is_deleted=False
            ).first()

            if not order:
                return Response(
                    {"success": False, "message": "Order not found.", "data": {}},
                    status=status.HTTP_404_NOT_FOUND,
                )

            rules = get_active_cashback_rules()
            credited_rewards = []

            # Order amount rewards
            for rule in rules.filter(rule_type="order_amount"):
                should_credit = False

                if rule.credit_on_status == "paid" and order.payment_status == "paid":
                    should_credit = True
                elif (
                    rule.credit_on_status == "delivered" and order.status == "delivered"
                ):
                    should_credit = True

                if (
                    should_credit
                    and Decimal(order.total_amount) >= rule.threshold_amount
                ):
                    reward_key = reward_key_for_order_rule(request.user, rule, order)

                    if not CashbackRewardLog.objects.filter(
                        reward_key=reward_key
                    ).exists():
                        credit_cashback_to_wallet(
                            user=request.user,
                            amount=rule.reward_amount,
                            source_type="order_reward",
                            rule=rule,
                            order=order,
                            remark=f"Cashback earned on order {order.order_number}",
                        )

                        CashbackRewardLog.objects.create(
                            user=request.user,
                            rule=rule,
                            order=order,
                            reward_key=reward_key,
                            credited_amount=rule.reward_amount,
                        )

                        credited_rewards.append(
                            {
                                "rule_title": rule.title,
                                "amount": rule.reward_amount,
                                "type": "order_amount",
                            }
                        )

                        create_app_notification(
                            request.user,
                            "Cashback Earned",
                            f"You earned ₹{rule.reward_amount} cashback on order {order.order_number}.",
                            "order",
                        )

            # Cumulative spend rewards
            for rule in rules.filter(rule_type="cumulative_spend"):
                if rule.cumulative_days <= 0:
                    continue

                should_credit = False
                if rule.credit_on_status == "paid" and order.payment_status == "paid":
                    should_credit = True
                elif (
                    rule.credit_on_status == "delivered" and order.status == "delivered"
                ):
                    should_credit = True

                if not should_credit:
                    continue

                window_end = timezone.now()
                window_start = window_end - timedelta(days=rule.cumulative_days)
                total_spend = get_cumulative_spend_for_days(
                    request.user, rule.cumulative_days
                )

                if total_spend >= rule.threshold_amount:
                    reward_key = reward_key_for_cumulative_rule(
                        request.user, rule, window_start, window_end
                    )

                    if not CashbackRewardLog.objects.filter(
                        reward_key=reward_key
                    ).exists():
                        credit_cashback_to_wallet(
                            user=request.user,
                            amount=rule.reward_amount,
                            source_type="cumulative_reward",
                            rule=rule,
                            order=order,
                            remark=f"Cumulative spend cashback earned in last {rule.cumulative_days} days.",
                        )

                        CashbackRewardLog.objects.create(
                            user=request.user,
                            rule=rule,
                            order=order,
                            reward_key=reward_key,
                            credited_amount=rule.reward_amount,
                        )

                        credited_rewards.append(
                            {
                                "rule_title": rule.title,
                                "amount": rule.reward_amount,
                                "type": "cumulative_spend",
                            }
                        )

                        create_app_notification(
                            request.user,
                            "Milestone Cashback Earned",
                            f"You earned ₹{rule.reward_amount} cashback for cumulative shopping milestone.",
                            "general",
                        )

            wallet = get_or_create_cashback_wallet(request.user)

            return Response(
                {
                    "success": True,
                    "message": "Cashback reward processing completed.",
                    "data": {
                        "credited_rewards": credited_rewards,
                        "wallet": CashbackWalletSerializer(wallet).data,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


class OrderStatusUpdateAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request):
        serializer = OrderStatusUpdateSerializer(data=request.data)

        if serializer.is_valid():
            order_id = serializer.validated_data["order_id"]
            new_status = serializer.validated_data["status"]

            order = Order.objects.filter(
                id=order_id, user=request.user, is_active=True, is_deleted=False
            ).first()

            if not order:
                return Response(
                    {"success": False, "message": "Order not found.", "data": {}},
                    status=status.HTTP_404_NOT_FOUND,
                )

            # order.status = new_status
            # previous_status = order.status

            # order.status = new_status
            previous_status = order.status

            order.status = new_status

            if new_status == "delivered":
                order.delivered_at = timezone.now()
            elif new_status == "cancelled":
                order.cancelled_at = timezone.now()

            order.save()
            # =====================================================
            # HANDLE STATUS AUTOMATION
            # =====================================================

            # if previous_status != new_status:

            #     handle_order_status_change(
            #         order=order,
            #         new_status=new_status,
            #     )

            try:
                invoice = create_or_update_invoice_for_order(order)
                if new_status == "delivered":
                    try:
                        send_invoice_email(invoice)
                    except Exception:
                        pass
            except Exception:
                pass

            # try:
            #     trigger_tally_sync_for_order(order)
            # except Exception:
            #     pass

            credited_rewards = process_cashback_for_order(order)
            wallet = get_or_create_cashback_wallet(request.user)

            create_app_notification(
                request.user,
                "Order Status Updated",
                f"Your order {order.order_number} status is now {new_status}.",
                "order",
            )

            return Response(
                {
                    "success": True,
                    "message": "Order status updated successfully.",
                    "data": {
                        # 'order': OrderDetailSerializer(order).data,
                        "order": OrderDetailSerializer(
                            order, context={"request": request}
                        ).data,
                        "credited_rewards": credited_rewards,
                        "wallet": CashbackWalletSerializer(wallet).data,
                    },
                },
                status=status.HTTP_200_OK,
            )

        return Response(
            {
                "success": False,
                "message": "Validation failed.",
                "errors": serializer.errors,
            },
            status=status.HTTP_400_BAD_REQUEST,
        )


# =========================================================
# INVOICE APIs
# =========================================================


class OrderInvoiceDetailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, order_id):
        order = Order.objects.filter(
            id=order_id, user=request.user, is_active=True, is_deleted=False
        ).first()

        if not order:
            return Response(
                {"success": False, "message": "Order not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        if not hasattr(order, "invoice_document"):
            invoice = create_or_update_invoice_for_order(order)
        else:
            invoice = order.invoice_document

        return Response(
            {
                "success": True,
                "message": "Invoice fetched successfully.",
                "data": InvoiceDocumentSerializer(
                    invoice, context={"request": request}
                ).data,
            },
            status=status.HTTP_200_OK,
        )


class OrderInvoiceEmailAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, order_id):
        order = Order.objects.filter(
            id=order_id, user=request.user, is_active=True, is_deleted=False
        ).first()

        if not order:
            return Response(
                {"success": False, "message": "Order not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        invoice = (
            order.invoice_document
            if hasattr(order, "invoice_document")
            else create_or_update_invoice_for_order(order)
        )

        try:
            send_invoice_email(invoice)
            return Response(
                {
                    "success": True,
                    "message": "Invoice emailed successfully.",
                    "data": InvoiceDocumentSerializer(
                        invoice, context={"request": request}
                    ).data,
                },
                status=status.HTTP_200_OK,
            )
        except Exception as e:
            return Response(
                {
                    "success": False,
                    "message": "Failed to email invoice.",
                    "errors": {"email": [str(e)]},
                },
                status=status.HTTP_400_BAD_REQUEST,
            )


# order tally sync api
# =========================================================
# TALLY SYNC APIs
# =========================================================


class OrderTallySyncRetryAPIView(APIView):
    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, order_id):
        order = Order.objects.filter(
            id=order_id, user=request.user, is_active=True, is_deleted=False
        ).first()

        if not order:
            return Response(
                {"success": False, "message": "Order not found.", "data": {}},
                status=status.HTTP_404_NOT_FOUND,
            )

        # log = trigger_tally_sync_for_order(order)

        return Response(
            {
                "success": True,
                "message": "Tally sync attempt completed.",
                "data": {
                    "sync_log_id": log.id,
                    "status": log.status,
                    "error_message": log.error_message,
                    "response_payload": log.response_payload,
                },
            },
            status=status.HTTP_200_OK,
        )
        
        
        
        
# =========================Shipment APIs================================
class ShipmentUpdateAPIView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    def post(self, request, shipment_id):
        if request.user.role != "admin":

            return Response(
                {
                    "success": False,
                    "message": "Permission denied.",
                },
                status=403,
            )
        shipment = Shipment.objects.filter(
            id=shipment_id,
            is_active=True,
            is_deleted=False,
        ).first()

        if not shipment:

            return Response(
                {
                    "success": False,
                    "message": "Shipment not found.",
                },
                status=404,
            )

        serializer = ShipmentUpdateSerializer(
            data=request.data,
        )

        if not serializer.is_valid():

            return Response(
                {
                    "success": False,
                    "message": "Validation failed.",
                    "errors": serializer.errors,
                },
                status=400,
            )

        data = serializer.validated_data

        shipment.courier_name = data.get(
            "courier_name",
            shipment.courier_name,
        )

        shipment.tracking_number = data.get(
            "tracking_number",
            shipment.tracking_number,
        )

        shipment.awb_number = data.get(
            "awb_number",
            shipment.awb_number,
        )

        shipment.estimated_delivery_date = data.get(
            "estimated_delivery_date",
            shipment.estimated_delivery_date,
        )

        shipment.save()

        update_shipment_status(
            shipment=shipment,
            shipment_status=data["shipment_status"],
        )

        return Response(
            {
                "success": True,
                "message": "Shipment updated successfully.",
                "data": ShipmentSerializer(
                    shipment,
                    context={"request": request},
                ).data,
            },
            status=200,
        )
        
        
        
class ShipmentListAPIView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    def get(self, request):

        if request.user.role != "admin":

            return Response(
                {
                    "success": False,
                    "message": "Permission denied.",
                },
                status=403,
            )
        shipments = Shipment.objects.filter(
            is_active=True,
            is_deleted=False,
        ).select_related(
            "order",
            "order__user",
        ).order_by("-created_at")

        serializer = ShipmentSerializer(
            shipments,
            many=True,
            context={"request": request},
        )

        return Response(
            {
                "success": True,
                "message": "Shipments fetched successfully.",
                "data": serializer.data,
            },
            status=200,
        )
        
        
        
class ShipmentDetailAPIView(APIView):

    permission_classes = [permissions.IsAuthenticated]

    def get(self, request, shipment_id):
        if request.user.role != "admin":
            return Response(
                {
                    "success": False,
                    "message": "Permission denied.",
                },
                status=403,
            )
        shipment = Shipment.objects.filter( 
            id=shipment_id,
            is_active=True,
            is_deleted=False,
        ).select_related(
            "order",
            "order__user",
        ).first()

        if not shipment:

            return Response(
                {
                    "success": False,
                    "message": "Shipment not found.",
                },
                status=404,
            )

        serializer = ShipmentSerializer(
            shipment,
            context={"request": request},
        )

        return Response(
            {
                "success": True,
                "message": "Shipment detail fetched successfully.",
                "data": serializer.data,
            },
            status=200,
        )
