from django.contrib import messages
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.utils.http import url_has_allowed_host_and_scheme
from django.views.decorators.http import require_POST

from .models import Dispatch, Order, Payment


def _authenticate_identifier(identifier, password):
    """Authenticate using a case-insensitive username or email identifier."""
    identifier = (identifier or "").strip()
    if not identifier or not password:
        return None

    try:
        account = User.objects.get(username__iexact=identifier)
    except User.DoesNotExist:
        account = None
    except User.MultipleObjectsReturned:
        return None

    if account is not None:
        return authenticate(username=account.username, password=password)

    try:
        account = User.objects.get(email__iexact=identifier)
    except User.DoesNotExist:
        return None
    except User.MultipleObjectsReturned:
        return None

    return authenticate(username=account.username, password=password)


def home(request):
    if request.user.is_authenticated:
        return redirect("dashboard")
    return redirect("login")


def staff_login(request):
    if request.user.is_authenticated:
        if request.user.is_active and (request.user.is_staff or request.user.is_superuser):
            return redirect("dashboard")
        logout(request)

    if request.method == "POST":
        identifier = request.POST.get("identifier", "")
        password = request.POST.get("password", "")
        user = _authenticate_identifier(identifier, password)

        # Portal access is for active staff accounts, not ordinary customer accounts.
        if user is not None and user.is_active and (user.is_staff or user.is_superuser):
            login(request, user)
            next_url = request.POST.get("next") or request.GET.get("next")
            if next_url and url_has_allowed_host_and_scheme(
                next_url,
                allowed_hosts={request.get_host()},
                require_https=request.is_secure(),
            ):
                return redirect(next_url)
            return redirect("dashboard")

        messages.error(request, "The username/email or password you entered is incorrect, or the account is not authorised for staff access.")

    return render(request, "accounts/login.html", {"next": request.GET.get("next", "")})


@login_required
def dashboard(request):
    user = request.user
    if not user.is_active or not (user.is_staff or user.is_superuser):
        logout(request)
        return redirect("login")

    # Django's superuser permission semantics are preserved; other users receive
    # only the explicitly assigned custom permissions through groups/user perms.
    permissions = {
        "can_view_orders": user.has_perm("core.skv_view_orders"),
        "can_accept_orders": user.has_perm("core.skv_accept_orders"),
        "can_decline_orders": user.has_perm("core.skv_decline_orders"),
        "can_hold_orders": user.has_perm("core.skv_hold_orders"),
        "can_edit_order_items": user.has_perm("core.skv_edit_order_items"),
        "can_view_sales": user.has_perm("core.skv_view_sales"),
        "can_place_orders": user.has_perm("core.skv_place_orders"),
        "can_view_payments": user.has_perm("core.skv_view_payments"),
        "can_verify_payments": user.has_perm("core.skv_verify_payments"),
        "can_reverse_payments": user.has_perm("core.skv_reverse_payments"),
        "can_view_dispatches": user.has_perm("core.skv_view_dispatches"),
        "can_assign_dispatches": user.has_perm("core.skv_assign_dispatches"),
        "can_update_dispatches": user.has_perm("core.skv_update_dispatches"),
        "can_view_catalogue": user.has_perm("core.skv_view_catalogue"),
        "can_edit_catalogue": user.has_perm("core.skv_edit_catalogue"),
        "can_change_prices": user.has_perm("core.skv_change_prices"),
        # These existing views currently enforce superuser-only access, so the
        # dashboard must not advertise them to group members who would be denied.
        "can_manage_staff": user.is_superuser,
        "can_manage_roles": user.is_superuser,
        "can_view_audit_logs": user.has_perm("core.skv_view_audit_logs"),
        # Existing staff/role/session screens remain superuser-only until their
        # own view-level permission checks are deliberately upgraded and tested.
        "can_manage_sessions": user.is_superuser,
    }

    order_counts = {}
    recent_orders = Order.objects.none()
    if permissions["can_view_orders"]:
        orders = Order.objects.select_related("customer", "assigned_to").all()
        order_counts = {
            "new": orders.filter(status=Order.Status.NEW).count(),
            "accepted": orders.filter(status=Order.Status.ACCEPTED).count(),
            "processing": orders.filter(status=Order.Status.PROCESSING).count(),
            "delivered": orders.filter(status=Order.Status.DELIVERED).count(),
        }
        recent_orders = orders.order_by("-created_at")[:8]

    if permissions["can_view_payments"]:
        order_counts["pending_payments"] = Payment.objects.filter(
            status__in=[Payment.Status.PENDING, Payment.Status.SUBMITTED, Payment.Status.RECEIVED]
        ).count()

    dispatch_count = 0
    if permissions["can_view_dispatches"]:
        dispatch_count = Dispatch.objects.filter(
            status__in=[Dispatch.Status.QUEUED, Dispatch.Status.ASSIGNED]
        ).count()

    return render(request, "dashboard.html", {
        "order_counts": order_counts,
        "recent_orders": recent_orders,
        "dispatch_count": dispatch_count,
        **permissions,
    })


@login_required
@require_POST
def staff_logout(request):
    logout(request)
    return redirect("login")


def db_status(request):
    # Diagnostic endpoint is intentionally restricted to active superusers.
    if not request.user.is_authenticated or not request.user.is_active or not request.user.is_superuser:
        raise PermissionDenied("Only an active administrator may view database diagnostics.")

    from django.db import connection
    try:
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1")
            cursor.fetchone()
        return HttpResponse("<h1>Database Connectivity</h1><p style='color:green;font-weight:bold'>DATABASE CONNECTION SUCCESSFUL</p>")
    except Exception:
        # Do not expose database exception details in a public response.
        return HttpResponse("<h1>Database connection failed</h1><p>Please check the application error log.</p>", status=500)
