# sales/views/barcode.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 barcode_pos(request):
    """Dedicated barcode scanner POS page — subscription-gated."""
    from core.utils import is_feature_enabled
    from core.models import Branch
    from accounts.audit import log_action

    if not is_feature_enabled('barcode_scanner'):
        messages.error(request, 'Barcode Scanner POS is not included in your subscription plan. Please contact support to upgrade.')
        return redirect('sales:pos')

    system_settings = SystemSettings.objects.first()

    # Ensure active session order
    order = None
    order_id = request.session.get('barcode_order_id')
    if order_id:
        try:
            order = POSOrder.objects.get(id=order_id, status='pending')
        except POSOrder.DoesNotExist:
            order = None

    if order is None:
        user_branch = getattr(request.user, 'branch', None) or Branch.objects.filter(is_active=True).first()
        order = POSOrder.objects.create(
            order_number=f"BORD-{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='cash',
            branch=user_branch,
        )
        request.session['barcode_order_id'] = order.id

    if request.method == 'POST':
        action = request.POST.get('action', '').strip()

        if action == 'complete_order':
            from decimal import Decimal
            from core.utils import check_limit_or_block
            from django.core.exceptions import PermissionDenied
            from sales.suspicious import detect_suspicious
            from core.email_utils import send_credit_customer_alert

            try:
                check_limit_or_block('orders_per_day')
            except PermissionDenied as e:
                messages.error(request, str(e))
                return redirect('sales:barcode_pos')

            payment_method = request.POST.get('payment_method', 'cash')
            customer_name = request.POST.get('customer_name', '')
            customer_phone = request.POST.get('customer_phone', '')
            amount_paid_str = request.POST.get('amount_paid', '')

            order_items = POSOrderItem.objects.filter(order=order)
            subtotal = sum(float(item.total_price) for item in order_items)

            # Promo / discount
            from decimal import Decimal as _D
            promo_code_v   = request.POST.get('promo_code', '').strip().upper()
            discount_raw   = request.POST.get('discount_amount', '0')
            try:
                discount_amt = min(_D(str(discount_raw)), _D(str(subtotal)))
                if discount_amt < 0:
                    discount_amt = _D('0')
            except Exception:
                discount_amt = _D('0')

            order.total_amount    = subtotal
            order.discount_amount = discount_amt
            order.final_amount    = max(0, subtotal - float(discount_amt))
            order.payment_method  = payment_method
            order.customer_name   = customer_name
            order.customer_phone  = customer_phone
            try:
                amount_paid = Decimal(str(amount_paid_str)) if amount_paid_str else Decimal(str(subtotal))
            except Exception:
                amount_paid = Decimal(str(subtotal))

            order.amount_paid = amount_paid
            order.balance_amount = max(Decimal(str(subtotal)) - amount_paid, Decimal('0'))
            if order.balance_amount > 0:
                order.payment_status = 'partial' if amount_paid > 0 else 'credit'
            else:
                order.payment_status = 'full'
            order.status = 'completed'
            order.save()

            if 'barcode_order_id' in request.session:
                del request.session['barcode_order_id']

            log_action(request, 'complete_order', target=f'Barcode Order #{order.order_number}')
            detect_suspicious(order)

            if order.balance_amount > 0 and customer_name:
                send_credit_customer_alert(customer_name, customer_phone, order.order_number, order.balance_amount)

            messages.success(request, f'Order #{order.order_number} completed!')
            return redirect('sales:print_receipt', order_id=order.id)

        elif action == 'clear_order':
            for item in order.items.all():
                item.product.stock_quantity += item.quantity
                item.product.save()
            order.delete()
            if 'barcode_order_id' in request.session:
                del request.session['barcode_order_id']
            messages.info(request, 'Barcode order cleared.')
            return redirect('sales:barcode_pos')

        elif action == 'update_qty':
            from decimal import Decimal as _D
            item_id = request.POST.get('item_id')
            delta   = int(request.POST.get('delta', 0))
            try:
                item = POSOrderItem.objects.select_related('product').get(id=item_id, order=order)
            except POSOrderItem.DoesNotExist:
                messages.error(request, 'Item not found.')
                return redirect('sales:barcode_pos')
            new_qty = item.quantity + delta
            if new_qty <= 0:
                # Remove from order and restore stock
                item.product.stock_quantity += item.quantity
                item.product.save()
                item.delete()
            else:
                enable_unlimited_stock = system_settings.enable_unlimited_stock if system_settings else False
                if delta > 0 and not enable_unlimited_stock and item.product.stock_quantity < delta:
                    messages.error(request, f'Only {item.product.stock_quantity} unit(s) left in stock.')
                    return redirect('sales:barcode_pos')
                # Resolve price (wholesale if qty meets threshold)
                ws_price   = float(item.product.wholesale_price or 0)
                ws_min_qty = int(item.product.wholesale_min_quantity or 0)
                unit_price = ws_price if (ws_price > 0 and ws_min_qty > 0 and new_qty >= ws_min_qty) else float(item.unit_price)
                if delta > 0:
                    item.product.stock_quantity -= delta
                elif delta < 0:
                    item.product.stock_quantity += abs(delta)
                item.product.save()
                item.quantity    = new_qty
                item.unit_price  = _D(str(unit_price))
                item.total_price = _D(str(unit_price)) * new_qty
                item.save()
            return redirect('sales:barcode_pos')

        elif action == 'remove_item':
            item_id = request.POST.get('item_id')
            try:
                item = POSOrderItem.objects.select_related('product').get(id=item_id, order=order)
                item.product.stock_quantity += item.quantity
                item.product.save()
                item.delete()
            except POSOrderItem.DoesNotExist:
                pass
            return redirect('sales:barcode_pos')

    order_items = POSOrderItem.objects.filter(order=order).select_related('product')
    subtotal = sum(float(item.total_price) for item in order_items)
    order.total_amount = subtotal
    order.final_amount = subtotal
    order.save()

      # Customer already imported via sales.models
    return render(request, 'sales/barcode_pos.html', {
        'order': order,
        'order_items': order_items,
        'subtotal': subtotal,
        'system_settings': system_settings,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
        'customers': Customer.objects.all().order_by('name'),
    })


@login_required

def api_scan_barcode(request):
    """AJAX: GET ?barcode=<code> → product JSON."""
    barcode = request.GET.get('barcode', '').strip()
    if not barcode:
        return JsonResponse({'ok': False, 'message': 'No barcode provided'}, status=400)

    product = Product.objects.filter(
        Q(barcode=barcode) | Q(sku=barcode), status='active'
    ).first()

    if not product:
        return JsonResponse({'ok': False, 'message': f'No product found for barcode: {barcode}'}, status=404)

    # Add to the current barcode order session
    order_id = request.session.get('barcode_order_id')
    item_id = None

    if order_id:
        try:
            order = POSOrder.objects.get(id=order_id, status='pending')
            settings = SystemSettings.objects.first()
            enable_unlimited_stock = settings.enable_unlimited_stock if settings else False

            if not enable_unlimited_stock and product.stock_quantity < 1:
                return JsonResponse({'ok': False, 'message': f'"{product.name}" is out of stock'}, status=400)

            existing = POSOrderItem.objects.filter(order=order, product=product).first()
            if existing:
                existing.quantity += 1
                existing.total_price = float(existing.unit_price) * existing.quantity
                existing.save()
                product.stock_quantity -= 1
                product.save()
                item_id = existing.id
            else:
                new_item = POSOrderItem.objects.create(
                    order=order, product=product,
                    quantity=1, unit_price=product.price,
                    total_price=float(product.price),
                )
                product.stock_quantity -= 1
                product.save()
                item_id = new_item.id

            # Recalc order total
            items = POSOrderItem.objects.filter(order=order)
            order.total_amount = sum(float(i.total_price) for i in items)
            order.final_amount = order.total_amount
            order.save()

        except POSOrder.DoesNotExist:
            item_id = None

    return JsonResponse({
        'ok': True,
        'product': {
            'id': product.id,
            'name': product.name,
            'sku': product.sku,
            'barcode': product.barcode,
            'price': float(product.price),
            'stock_quantity': product.stock_quantity,
            'item_id': item_id,
        }
    })


# ─────────────────────────────────────────────────────────────
# END-OF-DAY CASH RECONCILIATION  (#21)
# ─────────────────────────────────────────────────────────────

