# sales/views/pos.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 pos_sales(request):
    """Main POS sales screen with product selection dropdown"""
    # ------------------------------------------------------
    # 1. System settings + plan -> barcode_scanner_enabled
    # ------------------------------------------------------
    system_settings = SystemSettings.objects.first()
    barcode_scanner_enabled = True  # default

    if system_settings:
        try:
            license_obj = system_settings.license
            plan = license_obj.plan
            barcode_scanner_enabled = getattr(plan, "allow_barcode_scanner", True)
            logger.debug(f"DEBUG POS: Plan={plan.code}, allow_barcode_scanner={barcode_scanner_enabled}")
        except License.DoesNotExist:
            logger.debug("DEBUG POS: No license attached to SystemSettings; barcode_scanner_enabled default=True")
            barcode_scanner_enabled = True
    else:
        logger.debug("DEBUG POS: No SystemSettings found; barcode_scanner_enabled default=True")
        barcode_scanner_enabled = True

    # ------------------------------------------------------
    # 2. Get active products for dropdown
    # ------------------------------------------------------
    products = Product.objects.filter(status="active").order_by("name").values(
        "id", "name", "sku", "barcode", "price", "stock_quantity",
        "wholesale_price", "wholesale_min_quantity"
    )

    logger.debug(f"DEBUG POS: Found {len(products)} active products")

    # ------------------------------------------------------
    # 3. Ensure there is a current order in session
    # ------------------------------------------------------
    order = None
    order_id = request.session.get("current_order_id")

    if order_id:
        try:
            order = POSOrder.objects.get(id=order_id)
            logger.debug(f"DEBUG POS: Using existing order id={order.id}, number={order.order_number}")
        except POSOrder.DoesNotExist:
            logger.debug(f"DEBUG POS: Invalid order id in session ({order_id}); creating new order")
            order = None

    if order is None:
        # Determine branch for this order
        user_branch = getattr(request.user, "branch", None)
        if user_branch is None:
            # fallback: first active branch
            user_branch = Branch.objects.filter(is_active=True).first()

        order = POSOrder.objects.create(
            order_number=f"POS-{timezone.now().strftime('%m%d%H%M')}-{''.join(__import__('random').choices(__import__('string').ascii_uppercase+__import__('string').digits,k=5))}",
            total_amount=0,
            tax_amount=0,
            final_amount=0,
            cashier=request.user.username,
            payment_method="pos",
            branch=user_branch,
        )

        request.session["current_order_id"] = order.id
        logger.debug(f"DEBUG POS: Created new order id={order.id}, number={order.order_number}")

    # ------------------------------------------------------
    # 4. Handle POST actions
    # ------------------------------------------------------
    if request.method == "POST":
        action = (request.POST.get("action") or "").strip()
        logger.debug(f"DEBUG POS: POST action={action}")

        # ADD ITEM
        if action == "add_item":
            selected_sku = (request.POST.get("selected_product") or "").strip()
            try:
                quantity = int(request.POST.get("quantity") or "1")
            except ValueError:
                quantity = 1

            logger.debug(f"DEBUG POS: add_item selected_sku='{selected_sku}', quantity={quantity}")

            if not selected_sku:
                messages.error(request, "Please select a product.")
                return redirect("sales:pos")

            product = Product.objects.filter(sku=selected_sku, status="active").first()
            if not product:
                messages.error(request, f"Product not found with SKU: {selected_sku}")
                logger.debug(f"DEBUG POS: Product not found for SKU={selected_sku}")
                return redirect("sales:pos")

            enable_unlimited_stock = system_settings.enable_unlimited_stock if system_settings else False

            if not enable_unlimited_stock and product.stock_quantity < quantity:
                messages.error(
                    request,
                    f"Insufficient stock for {product.name}. Available: {product.stock_quantity}",
                )
                return redirect("sales:pos")

            existing_item = POSOrderItem.objects.filter(order=order, product=product).first()

            if existing_item:
                new_qty = existing_item.quantity + quantity
                if not enable_unlimited_stock:
                    max_allowed = product.stock_quantity + existing_item.quantity
                    if new_qty > max_allowed:
                        messages.error(request, f"Insufficient stock for {product.name}. Available: {product.stock_quantity}")
                        return redirect("sales:pos")

                # Re-evaluate unit price based on new total quantity (wholesale threshold)
                unit_price = product.price
                if (product.wholesale_price and product.wholesale_min_quantity
                        and product.wholesale_min_quantity > 0
                        and new_qty >= product.wholesale_min_quantity):
                    unit_price = product.wholesale_price

                existing_item.quantity = new_qty
                existing_item.unit_price = unit_price
                existing_item.total_price = float(unit_price) * new_qty
                existing_item.save()

                product.stock_quantity -= quantity
                product.save()

                ws_msg = f" (wholesale price applied!" if unit_price != product.price else ""
                messages.success(request, f"Added {quantity} more {product.name} to cart{ws_msg}")
            else:
                # Determine unit price — wholesale applies if qty meets threshold
                unit_price = product.price
                if (product.wholesale_price and product.wholesale_min_quantity
                        and product.wholesale_min_quantity > 0
                        and quantity >= product.wholesale_min_quantity):
                    unit_price = product.wholesale_price

                POSOrderItem.objects.create(
                    order=order,
                    product=product,
                    quantity=quantity,
                    unit_price=unit_price,
                    total_price=float(unit_price) * quantity,
                )

                product.stock_quantity -= quantity
                product.save()

                ws_msg = " (wholesale price applied!)" if unit_price != product.price else ""
                messages.success(request, f"Added {quantity} {product.name} to cart{ws_msg}")

            return redirect("sales:pos")

        # REMOVE ITEM
        elif action == "remove_item":
            item_id = request.POST.get("item_id")
            logger.debug(f"DEBUG POS: remove_item id={item_id}")
            try:
                order_item = get_object_or_404(POSOrderItem, id=item_id, order=order)
                order_item.product.stock_quantity += order_item.quantity
                order_item.product.save()
                order_item.delete()
                messages.success(request, "Item removed from cart")
                logger.debug(f"DEBUG POS: Removed item id={item_id}")
            except Exception as exc:
                messages.error(request, "Error removing item")
                logger.debug(f"DEBUG POS: Error removing item id={item_id}: {exc}")
            return redirect("sales:pos")

        # CLEAR ORDER
        elif action == "clear_order":
            logger.debug(f"DEBUG POS: clear_order for order id={order.id}")
            for item in order.items.all():
                item.product.stock_quantity += item.quantity
                item.product.save()
                print(
                    f"DEBUG POS: Restored stock for {item.product.name}, "
                    f"+{item.quantity}, new_stock={item.product.stock_quantity}"
                )
            order.delete()
            if "current_order_id" in request.session:
                del request.session["current_order_id"]
            messages.info(request, "Current order cleared")
            logger.debug("DEBUG POS: Order cleared and session key removed")
            return redirect("sales:pos")

        # COMPLETE ORDER
        elif action == "complete_order":
            logger.debug(f"DEBUG POS: complete_order for order id={order.id}")

            # enforce plan daily order limit
            try:
                check_limit_or_block("orders_per_day")
            except PermissionDenied as e:
                messages.error(request, str(e))
                logger.debug(f"DEBUG POS: orders_per_day blocked: {e}")
                return redirect("sales:pos")

            payment_method = request.POST.get("payment_method", "pos")
            reference_number = request.POST.get("reference_number", "")
            customer_name = request.POST.get("customer_name", "")
            customer_phone = request.POST.get("customer_phone", "")

            print(
                f"DEBUG POS: Completing order={order.order_number}, "
                f"payment_method={payment_method}, customer={customer_name}, phone={customer_phone}"
            )

            # recalc totals
            order_items = POSOrderItem.objects.filter(order=order).select_related("product")
            subtotal = sum(float(item.total_price) for item in order_items)
            tax_amount = subtotal * 0.00
            final_total = subtotal + tax_amount

            order.total_amount = subtotal
            order.tax_amount = tax_amount
            order.final_amount = final_total
            order.payment_method = payment_method
            order.customer_name = customer_name
            order.customer_phone = customer_phone
            order.status = "completed"
            order.save()

            if "current_order_id" in request.session:
                del request.session["current_order_id"]

            messages.success(request, f"Order #{order.order_number} completed successfully!")
            logger.debug(f"DEBUG POS: Order {order.order_number} completed successfully")
            return redirect("sales:print_receipt", order_id=order.id)

        # UNKNOWN ACTION
        else:
            logger.debug(f"DEBUG POS: Unknown POST action='{action}', redirecting to POS")
            return redirect("sales:pos")

    # ------------------------------------------------------
    # 5. GET request: render POS with totals
    # ------------------------------------------------------
    order_items = POSOrderItem.objects.filter(order=order).select_related("product")

    subtotal = sum(float(item.total_price) for item in order_items)
    tax_amount = subtotal * 0.00
    final_total = subtotal + tax_amount

    order.total_amount = subtotal
    order.tax_amount = tax_amount
    order.final_amount = final_total
    order.save()

    print(
        f"DEBUG POS: GET render, order={order.order_number}, "
        f"items={order_items.count()}, subtotal={subtotal}, final_total={final_total}"
    )

    # Customer is imported from sales.models at top of file
    context = {
        "order": order,
        "order_items": order_items,
        "subtotal": subtotal,
        "tax_amount": tax_amount,
        "final_total": final_total,
        "products": products,
        "system_settings": system_settings,
        "user_role": request.user.role,
        "user_name": request.user.get_full_name() or request.user.username,
        "barcode_scanner_enabled": barcode_scanner_enabled,
        "customers": Customer.objects.all().order_by('name'),
    }
    return render(request, "sales/pos_sales.html", context)

def pos_grid(request):
    """Smart Grid POS V2 — gated by plan.allow_grid_pos"""
    system_settings = SystemSettings.objects.first()
    try:
        from core.utils import get_current_license
        lic = get_current_license()
        plan = getattr(lic, 'plan', None)
        if plan and not getattr(plan, 'allow_grid_pos', False):
            from django.urls import reverse
            return redirect(reverse('upgrade_required') + '?feature=Smart+Grid+POS+V2&required_plan=Standard')
    except Exception:
        pass

    # Customer is imported from sales.models at top of file
    context = {
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
        'system_settings': system_settings,
        'customers': Customer.objects.all().order_by('name'),
    }
    return render(request, 'sales/pos_grid.html', context)


