from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib import messages
from django.http import JsonResponse
from django.core.exceptions import PermissionDenied

from .models import SystemSettings, FieldCategory, CustomField, DynamicFormData, Branch, PromoCode
from .forms import SystemSettingsForm, FieldCategoryForm, CustomFieldForm, BranchForm
from .utils import DynamicFormEngine, get_current_license, is_feature_enabled
from accounts.decorators import role_required

# core/views.py (Dashboard with real data)
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.utils import timezone
from django.db.models import Sum, Count, Q
from datetime import datetime, timedelta
from inventory.models import Product
from accounts.models import CustomUser
from sales.models import POSOrder, POSOrderItem, DailySalesSummary

@login_required
def home(request):
    if request.user.is_authenticated:
        return redirect('dashboard')
    return render(request, 'core/home.html')

def activate_system(request):
    system = SystemSettings.objects.first()
    if not system or system.is_activated:
        return redirect('dashboard')
    
    if request.method == 'POST':
        code = request.POST.get('activation_code', '').strip()
        
        # User requested: only odd characters of the generated 30 char code are correct
        correct_code = system.activation_code[::2]
        
        if code == correct_code:
            system.is_activated = True
            system.save()
            messages.success(request, 'System activated successfully!')
            return redirect('dashboard')
        else:
            messages.error(request, 'Invalid activation code.')
            
    return render(request, 'core/activate.html')

@login_required
@role_required(['admin', 'manager'])
def dashboard(request):
    """Main dashboard with real data"""
    today = timezone.now().date()
    
    # Get today's summary
    today_summary = DailySalesSummary.objects.filter(date=today).first()

    # If no summary exists, calculate fresh
    if not today_summary:
        today_orders = POSOrder.objects.filter(branch=branch)

# Restrict managers/cashiers
        today_orders = filter_orders_by_user_branch(request, orders)

        today_sales = today_orders.aggregate(total=Sum('final_amount'))['total'] or 0
        today_transactions = today_orders.count()
        today_customers = today_orders.values('customer_name','customer_phone').distinct().count()
        avg_order_value = today_orders.aggregate(avg=Avg('final_amount'))['avg'] or 0
    else:
        today_sales = today_summary.total_revenue
        today_transactions = today_summary.total_transactions
        today_customers = today_summary.total_customers
        avg_order_value = today_summary.average_order_value

    # Inventory data
    total_inventory = Product.objects.count()
    low_stock_products = Product.objects.filter(
        stock_status__in=['low_stock', 'out_of_stock']
    ).count()

    # User data
    total_users = CustomUser.objects.count()
    active_users = CustomUser.objects.filter(is_active=True).count()

    # Timeline activities
    recent_orders = POSOrder.objects.filter(
        created_at__date=today,
        status='completed'
    ).order_by('-created_at')[:3]

    from inventory.models import InventoryTransaction
    recent_inventory_updates = InventoryTransaction.objects.filter(
        created_at__date=today
    ).order_by('-created_at')[:3]

    recent_users = CustomUser.objects.filter(
        date_joined__date=today
    ).order_by('-date_joined')[:3]

    activities = []

    # Orders
    for order in recent_orders:
        activities.append({
            'type': 'sale',
            'title': f'POS Sale #{order.order_number}',
            'amount': order.final_amount,
            'time': order.created_at.strftime('%H:%M'),
            'icon': 'fas fa-cash-register',
            'color': 'primary'
        })

    # Inventory
    for update in recent_inventory_updates:
        activities.append({
            'type': 'inventory',
            'title': f'{update.transaction_type.title()} Stock',
            'product': update.product.name,
            'quantity': update.quantity,
            'time': update.created_at.strftime('%H:%M'),
            'icon': 'fas fa-box',
            'color': 'success'
        })

    # New users
    for user in recent_users:
        activities.append({
            'type': 'user',
            'title': f'New User: {user.username}',
            'time': user.date_joined.strftime('%H:%M'),
            'icon': 'fas fa-user-plus',
            'color': 'info'
        })

    activities.sort(key=lambda x: x['time'], reverse=True)

    # Top selling items (last 24 hours)
    last_24h_start = timezone.now() - timedelta(hours=24)

    top_selling_items = (
        POSOrderItem.objects.filter(
            order__created_at__gte=last_24h_start,
            order__status='completed'
        )
        .values('product__name', 'product__sku')
        .annotate(
            total_quantity=Sum('quantity'),
            total_revenue=Sum('total_price')
        )
        .order_by('-total_quantity')[:5]
    )

    # ── Weekly chart data (last 7 days) ──
    import json
    weekly_labels = []
    weekly_revenue_data = []
    weekly_orders_data = []
    for i in range(6, -1, -1):
        day = today - timedelta(days=i)
        day_orders = POSOrder.objects.filter(
            created_at__date=day,
            status='completed'
        )
        rev = day_orders.aggregate(total=Sum('final_amount'))['total'] or 0
        cnt = day_orders.count()
        weekly_labels.append(day.strftime('%a'))
        weekly_revenue_data.append(float(rev))
        weekly_orders_data.append(cnt)

    # ── Yesterday stats ──
    yesterday = today - timedelta(days=1)
    yesterday_qs = POSOrder.objects.filter(created_at__date=yesterday, status='completed')
    yesterday_sales = yesterday_qs.aggregate(total=Sum('final_amount'))['total'] or 0
    yesterday_transactions = yesterday_qs.count()

    # Growth
    if yesterday_sales > 0:
        sales_growth_percentage = ((float(today_sales) - float(yesterday_sales)) / float(yesterday_sales)) * 100
    else:
        sales_growth_percentage = 0

    # ── Weekly / Monthly totals ──
    week_start = today - timedelta(days=today.weekday())
    month_start = today.replace(day=1)
    weekly_qs = POSOrder.objects.filter(created_at__date__gte=week_start, status='completed')
    monthly_qs = POSOrder.objects.filter(created_at__date__gte=month_start, status='completed')
    weekly_sales = weekly_qs.aggregate(total=Sum('final_amount'))['total'] or 0
    weekly_transactions = weekly_qs.count()
    monthly_sales = monthly_qs.aggregate(total=Sum('final_amount'))['total'] or 0
    monthly_transactions = monthly_qs.count()

    # ── Inventory detail ──
    in_stock_products = Product.objects.filter(stock_status='in_stock').count()
    out_of_stock_products = Product.objects.filter(stock_status='out_of_stock').count()

    # ── Recent orders (queryset for template) ──
    recent_orders_qs = POSOrder.objects.filter(
        created_at__date=today, status='completed'
    ).select_related('customer').order_by('-created_at')[:6]

    # ── Payment breakdown ──
    payment_breakdown = []
    total_today = float(today_sales) or 1
    for method_code, method_label in [('cash','Cash'),('bank_transfer','Bank Transfer'),('pos_card','POS/Card'),('other','Other')]:
        method_total = POSOrder.objects.filter(
            created_at__date=today,
            status='completed',
            payment_method=method_code
        ).aggregate(total=Sum('final_amount'))['total'] or 0
        if method_total:
            payment_breakdown.append({
                'label': method_label,
                'total': float(method_total),
                'percentage': round(float(method_total) / total_today * 100, 1),
            })

    # ── Cashier performance ──
    from django.db.models import Count
    cashier_performance = (
        POSOrder.objects.filter(created_at__date=today, status='completed')
        .values('cashier')
        .annotate(total_orders=Count('id'), total_sales=Sum('final_amount'))
        .order_by('-total_sales')[:8]
    )

    context = {
        'today_sales': today_sales,
        'today_transactions': today_transactions,
        'today_customers': today_customers,
        'avg_order_value': avg_order_value,
        'yesterday_sales': yesterday_sales,
        'yesterday_transactions': yesterday_transactions,
        'weekly_sales': weekly_sales,
        'weekly_transactions': weekly_transactions,
        'monthly_sales': monthly_sales,
        'monthly_transactions': monthly_transactions,
        'sales_growth_percentage': sales_growth_percentage,
        'total_inventory': total_inventory,
        'in_stock_products': in_stock_products,
        'low_stock_products': low_stock_products,
        'out_of_stock_products': out_of_stock_products,
        'total_users': total_users,
        'active_users': active_users,
        'top_selling_items': top_selling_items,
        'recent_orders': recent_orders_qs,
        'payment_breakdown': payment_breakdown,
        'cashier_performance': cashier_performance,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
        # Chart.js data (JSON-safe)
        'weekly_labels': json.dumps(weekly_labels),
        'weekly_revenue_data': json.dumps(weekly_revenue_data),
        'weekly_orders_data': json.dumps(weekly_orders_data),
    }
    return render(request, 'accounts/dashboard.html', context)

    

@login_required
@role_required('admin')
def system_settings(request):
    # Get or create the system settings instance
    settings, created = SystemSettings.objects.get_or_create(pk=1)

    if request.method == 'POST':
        form = SystemSettingsForm(request.POST, request.FILES, instance=settings)
        if form.is_valid():
            form.save()
            messages.success(request, 'Settings saved successfully!')
            return redirect('system_settings')
        else:
            # Show each error as a message so nothing is lost silently
            for field, errors in form.errors.items():
                for err in errors:
                    label = form.fields[field].label if field in form.fields else field
                    messages.error(request, f'{label}: {err}')
            print("Settings form errors:", form.errors)  # server-side debug
    else:
        form = SystemSettingsForm(instance=settings)

    context = {
        'form': form,
        'settings': settings,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    }
    return render(request, 'core/system_settings.html', context)



@login_required
@role_required('admin')
def promo_list(request):
    promos = PromoCode.objects.all()
    return render(request, 'core/promo_list.html', {
        'promos': promos,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    })


@login_required
@role_required('admin')
def promo_create(request):
    if request.method == 'POST':
        code = request.POST.get('code', '').strip().upper()
        description = request.POST.get('description', '').strip()
        discount_type = request.POST.get('discount_type', 'percentage')
        discount_value = request.POST.get('discount_value', '0')
        max_uses = request.POST.get('max_uses', '0')
        minimum_order_amount = request.POST.get('minimum_order_amount', '0')
        expires_at_raw = request.POST.get('expires_at', '').strip() or None

        if not code:
            messages.error(request, 'Code is required.')
            return redirect('promo_create')

        if PromoCode.objects.filter(code__iexact=code).exists():
            messages.error(request, f'Code "{code}" already exists.')
            return redirect('promo_create')

        PromoCode.objects.create(
            code=code, description=description, discount_type=discount_type,
            discount_value=discount_value, max_uses=max_uses,
            minimum_order_amount=minimum_order_amount, expires_at=expires_at_raw,
        )
        messages.success(request, f'Promo code "{code}" created!')
        return redirect('promo_list')

    return render(request, 'core/promo_form.html', {
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    })


@login_required
@role_required('admin')
def promo_toggle(request, pk):
    promo = get_object_or_404(PromoCode, pk=pk)
    promo.is_active = not promo.is_active
    promo.save()
    status = 'activated' if promo.is_active else 'deactivated'
    messages.success(request, f'Promo "{promo.code}" {status}.')
    return redirect('promo_list')


@login_required
@role_required('admin')
def promo_delete(request, pk):
    promo = get_object_or_404(PromoCode, pk=pk)
    if request.method == 'POST':
        code = promo.code
        promo.delete()
        messages.success(request, f'Promo "{code}" deleted.')
        return redirect('promo_list')
    return render(request, 'core/promo_confirm_delete.html', {
        'promo': promo,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    })

@login_required
@role_required('admin')
def get_current_settings():

    """Helper function to get current system settings"""
    settings, created = SystemSettings.objects.get_or_create(pk=1)
    return settings


    # ==========================
# Branch Management Views
# ==========================

@login_required
@role_required('admin')
def branch_list(request):
    """
    List all branches. If no branches exist, create a default MAIN branch.
    """
    # Ensure at least one branch exists
    if not Branch.objects.exists():
        settings = SystemSettings.objects.first()
        default_name = settings.business_name if settings else "Main Branch"
        Branch.objects.create(
            name=default_name,
            code="MAIN",
            is_active=True,
        )

    license_obj = get_current_license()
    plan = getattr(license_obj, "plan", None)
    allow_multi_branch = bool(plan and getattr(plan, "allow_multi_branch", False))

    branches = Branch.objects.all().order_by('name')

    context = {
        "branches": branches,
        "allow_multi_branch": allow_multi_branch,
    }
    return render(request, "core/branch_list.html", context)


@login_required
@role_required('admin')
def branch_create(request):
    """
    Create a new branch – only allowed if plan.allow_multi_branch is True.
    """
    if not is_feature_enabled("multi_branch"):
        messages.error(request, "Your subscription plan does not allow multiple branches. Please upgrade to enable this feature.")
        return redirect('branch_list')

    if request.method == "POST":
        form = BranchForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Branch created successfully.")
            return redirect('branch_list')
    else:
        form = BranchForm()

    return render(request, "core/branch_form.html", {"form": form, "mode": "create"})


@login_required
@role_required('admin')
def branch_update(request, pk):
    """
    Edit an existing branch. Even on single-branch plans, editing the MAIN branch should be allowed.
    """
    branch = get_object_or_404(Branch, pk=pk)

    if request.method == "POST":
        form = BranchForm(request.POST, instance=branch)
        if form.is_valid():
            form.save()
            messages.success(request, "Branch updated successfully.")
            return redirect('branch_list')
    else:
        form = BranchForm(instance=branch)

    return render(request, "core/branch_form.html", {"form": form, "mode": "edit", "branch": branch})


@login_required
@role_required('admin')
def branch_delete(request, pk):
    """
    Delete a branch. Prevent deletion if it's the only branch.
    """
    branch = get_object_or_404(Branch, pk=pk)

    if Branch.objects.count() <= 1:
        messages.error(request, "You must have at least one branch.")
        return redirect('branch_list')

    if request.method == "POST":
        branch.delete()
        messages.success(request, "Branch deleted successfully.")
        return redirect('branch_list')

    return render(request, "core/branch_confirm_delete.html", {"branch": branch})

# core/views.py

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden
from django.utils import timezone
from django.db.models import Sum, Count
from sales.models import POSOrder
from accounts.models import CustomUser
from .models import Branch

@login_required
@role_required('admin')
def branch_detail(request, pk):
    """
    Branch detail page – shows sales and users for this branch.
    Respects roles:
      - superadmin/admin → can view any branch
      - manager/cashier → only their own branch
    """
    branch = get_object_or_404(Branch, pk=pk)
    user = request.user

    if user.role in ("manager", "cashier") and user.branch_id != branch.id:
        return HttpResponseForbidden("You are not allowed to view other branches.")

    today = timezone.now().date()
    month_start = today.replace(day=1)

    orders_today = POSOrder.objects.filter(
        branch=branch,
        status="completed",
        created_at__date=today,
    )

    orders_month = POSOrder.objects.filter(
        branch=branch,
        status="completed",
        created_at__date__gte=month_start,
        created_at__date__lte=today,
    )

    today_sales = orders_today.aggregate(total=Sum("final_amount"))["total"] or 0
    month_sales = orders_month.aggregate(total=Sum("final_amount"))["total"] or 0
    total_orders_today = orders_today.count()
    total_orders_month = orders_month.count()

    branch_users = CustomUser.objects.filter(branch=branch).order_by("role", "username")

    context = {
        "branch": branch,
        "users": branch_users,
        "today_sales": today_sales,
        "month_sales": month_sales,
        "total_orders_today": total_orders_today,
        "total_orders_month": total_orders_month,
        "orders_today": orders_today.order_by("-created_at")[:20],
        "user_role": user.role,
        "user_name": user.get_full_name() or user.username,
    }
    return render(request, "core/branch_detail.html", context)



@login_required
@role_required('admin')
def field_builder(request):
    if request.method == 'POST':
        if 'create_category' in request.POST:
            category_form = FieldCategoryForm(request.POST)
            if category_form.is_valid():
                category_form.save()
                messages.success(request, 'Category created successfully!')
                return redirect('field_builder')
        elif 'create_field' in request.POST:
            field_form = CustomFieldForm(request.POST)
            if field_form.is_valid():
                field_form.save()
                messages.success(request, 'Custom field created successfully!')
                return redirect('field_builder')
    else:
        category_form = FieldCategoryForm()
        field_form = CustomFieldForm()
    
    categories = FieldCategory.objects.prefetch_related('fields').all()
    
    context = {
        'categories': categories,
        'category_form': category_form,
        'field_form': field_form,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    }
    return render(request, 'core/field_builder.html', context)

@login_required
@role_required('admin')
def edit_field(request, field_id):
    field = get_object_or_404(CustomField, id=field_id)
    
    if request.method == 'POST':
        form = CustomFieldForm(request.POST, instance=field)
        if form.is_valid():
            form.save()
            messages.success(request, 'Field updated successfully!')
            return redirect('field_builder')
    else:
        form = CustomFieldForm(instance=field)
    
    context = {
        'form': form,
        'field': field,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    }
    return render(request, 'core/edit_field.html', context)

@login_required
@role_required('admin')
def delete_field(request, field_id):
    field = get_object_or_404(CustomField, id=field_id)
    field_name = field.name
    field.delete()
    messages.success(request, f'Field "{field_name}" deleted successfully!')
    return redirect('field_builder')


@login_required
@role_required('admin')
def dynamic_form_test(request):
    """Test view to demonstrate dynamic form rendering"""
    if request.method == 'POST':
        try:
            # Process form data
            form_data = {}
            for key, value in request.POST.items():
                if key.startswith('field_') and value:  # Dynamic fields start with 'field_'
                    field_name = key.replace('field_', '')
                    form_data[field_name] = value
            
            # Process with dynamic form engine
            dynamic_form = DynamicFormEngine.process_form_data(
                content_type='test_form',
                object_id=1,
                form_data=form_data
            )
            
            messages.success(request, 'Form data saved successfully!')
            return redirect('dynamic_form_test')
            
        except Exception as e:
            messages.error(request, f'Error saving form: {str(e)}')
    
    # Render dynamic form
    form_html = DynamicFormEngine.render_form_fields('test_form')
    
    context = {
        'form_html': form_html,
        'user_role': request.user.role,
        'user_name': request.user.get_full_name() or request.user.username,
    }
    return render(request, 'core/dynamic_form_test.html', context)

@login_required
@role_required('admin')
def get_form_data(request, content_type, object_id):
    """AJAX endpoint to get form data"""
    try:
        data = DynamicFormEngine.get_form_data(content_type, object_id)
        return JsonResponse({'success': True, 'data': data})
    except Exception as e:
        return JsonResponse({'success': False, 'error': str(e)})
        
        
        
from django.shortcuts import render

def offline(request):
    """
    Shown when the service worker can't reach network and no cached page is available.
    """
    return render(request, 'core/offline.html')


def upgrade_required(request):
    """Feature lock page - shown when a plan-gated feature is accessed."""
    feature_name = request.GET.get('feature', 'This Feature')
    required_plan = request.GET.get('required_plan', 'Standard')
    return render(request, 'core/upgrade_required.html', {
        'feature_name': feature_name,
        'required_plan': required_plan,
    })


# ─────────────────────────────────────────────────────────────────
# CUSTOM ERROR HANDLERS
# ─────────────────────────────────────────────────────────────────

def error_400(request, exception=None):
    """400 Bad Request"""
    return render(request, 'errors/400.html', status=400)


def error_403(request, exception=None):
    """403 Forbidden / Permission Denied"""
    return render(request, 'errors/403.html', status=403)


def error_404(request, exception=None):
    """404 Page Not Found"""
    return render(request, 'errors/404.html', status=404)


def error_500(request):
    """500 Internal Server Error"""
    return render(request, 'errors/500.html', status=500)


def error_503(request, exception=None):
    """503 Service Unavailable"""
    return render(request, 'errors/503.html', status=503)