# sales/views/api_order.py
import logging
import json
import csv
import string
from datetime import datetime, timedelta
from decimal import Decimal

from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils import timezone
from django.db import transaction
from django.db.models import Sum, Count, Q, F
from django.core.exceptions import PermissionDenied

from inventory.models import Product
from core.models import (
    SystemSettings, CustomField, DynamicFormData,
    SubscriptionPlan, License, Branch,
)
from core.utils import check_limit_or_block, filter_orders_by_user_branch
from accounts.decorators import role_required
from sales.models import (
    POSOrder, POSOrderItem, PaymentTransaction,
    DailySalesSummary, UnusualTransaction, Customer,
)
from sales.forms import POSOrderForm, POSOrderItemForm

logger = logging.getLogger(__name__)


def api_create_order(request):
    """JSON endpoint for creating POS orders (used by offline sync)."""
    try:
        data = json.loads(request.body.decode("utf-8"))
    except json.JSONDecodeError:
        return JsonResponse({"success": False, "error": "Invalid JSON"}, status=400)

    items = data.get("items") or []
    if not items:
        return JsonResponse({"success": False, "error": "No items"}, status=400)

    totals = data.get("totals") or {}
    payment_method = data.get("payment_method") or "pos"
    reference = data.get("reference_number") or ""
    customer_name = data.get("customer_name") or ""
    customer_phone = data.get("customer_phone") or ""
    client_id = data.get("client_id")

    # ── Rate limiting (re-uses existing limit check) ──────────────
    try:
        check_limit_or_block("orders_per_day")
    except Exception as e:
        return JsonResponse({"success": False, "error": str(e)}, status=429)

    # ── Client-ID deduplication for offline retries ────────────────
    client_id = data.get("client_id") or ""
    if client_id:
        existing = POSOrder.objects.filter(client_id=client_id).first()
        if existing:
            return JsonResponse({
                "success": True,
                "order_id": existing.id,
                "order_number": existing.order_number,
                "redirect_url": f"/sales/receipt/{existing.id}/",
                "client_id": client_id,
                "duplicate": True,
            })

    try:
        with transaction.atomic():
            try:
                subtotal = Decimal(str(totals.get("subtotal", 0)))
                grand_total = Decimal(
                    str(totals.get("grand_total", totals.get("grandTotal", subtotal)))
                )
            except Exception:
                subtotal = Decimal("0")
                for item in items:
                    price = Decimal(str(item.get("price", 0)))
                    qty = int(item.get("quantity") or 1)
                    subtotal += price * qty
                grand_total = subtotal

            # NEW: handle payment status + amount paid
            payment_status = data.get("payment_status") or "full"
            raw_amount_paid = data.get("amount_paid")

            try:
                amount_paid = None
                if raw_amount_paid not in (None, "",):
                    amount_paid = Decimal(str(raw_amount_paid))
            except Exception:
                amount_paid = None

            # Logic:
            # - full: amount_paid = grand_total (if empty)
            # - partial/credit: if empty -> 0
            if payment_status == "full":
                if amount_paid is None:
                    amount_paid = grand_total
            else:
                if amount_paid is None:
                    amount_paid = Decimal("0")

            if amount_paid < 0:
                amount_paid = Decimal("0")
            if amount_paid > grand_total:
                amount_paid = grand_total

            balance_amount = grand_total - amount_paid

            user_branch = getattr(request.user, "branch", None)

            if user_branch is None:
                # fallback to first active branch so ALL orders have a branch
                user_branch = Branch.objects.filter(is_active=True).first()

            # ── Mixed alphanumeric order number (API terminal) ─────
            import string as _str, random as _rand
            _suffix = ''.join(_rand.choices(_str.ascii_uppercase + _str.digits, k=5))
            _order_number = f"ORD-{timezone.now().strftime('%m%d%H%M')}-{_suffix}"

            # ── Read and apply promo/discount ──────────────────────────
            promo_code_val    = data.get("promo_code", "")
            disc_raw          = data.get("discount_amount", 0)
            try:
                discount_amount = min(Decimal(str(disc_raw)), subtotal)
                if discount_amount < 0:
                    discount_amount = Decimal("0")
            except Exception:
                discount_amount = Decimal("0")

            # Apply discount to grand total
            grand_total = Decimal(
                str(totals.get("grand_total", totals.get("grandTotal", subtotal)))
            )
            # If client sends discount separately, recalculate final
            if discount_amount > 0:
                grand_total = max(Decimal("0"), subtotal - discount_amount)

            order = POSOrder.objects.create(
                order_number=_order_number,
                client_id=client_id,
                total_amount=subtotal,
                tax_amount=Decimal("0"),
                discount_amount=discount_amount,
                final_amount=grand_total,
                payment_method=payment_method,
                status="completed",
                payment_status=payment_status,
                amount_paid=amount_paid,
                balance_amount=grand_total - amount_paid if amount_paid is not None else grand_total,
                customer_name=customer_name,
                customer_phone=customer_phone,
                cashier=request.user.username,
                branch=user_branch,
            )

            # (your existing loop creating POSOrderItem + reducing stock stays the same)
            # (your existing loop creating POSOrderItem + reducing stock stays the same)
            
                        # ---------- FIX: CREATE ORDER ITEMS ----------
            raw_items = (
                data.get("items")
                or data.get("cart")
                or data.get("cartItems")
                or data.get("products")
                or []
            )
            
            for item in raw_items:
                # Try different possible field names
                product_id = (
                    item.get("product_id")
                    or item.get("productId")
                    or item.get("id")
                    or item.get("product")
                )
            
                if not product_id:
                    continue  # skip invalid entry
            
                qty = int(item.get("quantity") or item.get("qty") or 1)
                price = Decimal(str(item.get("price") or item.get("unit_price") or "0"))
            
                # Create line item
                POSOrderItem.objects.create(
                    order=order,
                    product_id=product_id,
                    quantity=qty,
                    unit_price=price,
                    total_price=price * qty,
                )
                # Reduce stock safely
                product = Product.objects.select_for_update().get(id=product_id)
                
                settings = SystemSettings.objects.first()
                enable_unlimited_stock = settings.enable_unlimited_stock if settings else False

                if product.stock_quantity < qty and not enable_unlimited_stock:
                    raise ValueError(f"Insufficient stock for '{product.name}': only {product.stock_quantity} left.")
                product.stock_quantity -= qty
                product.save(update_fields=['stock_quantity'])
                # Snapshot product name on the order item
                POSOrderItem.objects.filter(order=order, product_id=product_id, quantity=qty).update(
                    product_name=product.name
                )
            # Record only what was actually paid now
            if amount_paid > 0:
                PaymentTransaction.objects.create(
                    order=order,
                    payment_method=payment_method,
                    amount=amount_paid,
                    reference_number=reference,
                    status="completed",
                )

    except ValueError as e:
        # Stock / validation conflicts ? tell client clearly
        return JsonResponse(
            {"success": False, "error": str(e), "code": "STOCK_CONFLICT"},
            status=400,
        )
    except Exception as e:
        # Unexpected error
        return JsonResponse(
            {"success": False, "error": "Server error"}, status=500
        )

    return JsonResponse(
        {
            "success": True,
            "order_id": order.id,
            "order_number": order.order_number,
            "redirect_url": f"/sales/receipt/{order.id}/",
            "client_id": client_id,
        }
    )
from django.db.models import Sum, Count, Max  # combined with top-level import


@login_required
@role_required(['admin', 'manager'])
def placeholder_stub():
    pass  # placeholder removed below
