from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.admin.views.decorators import staff_member_required
from django.views.decorators.http import require_POST
from django.contrib import messages
from django.urls import reverse
from django.contrib.auth.models import User
from django.contrib.auth.views import LoginView

from api.models import Profile, Opportunity, IntroductionRequest
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
import django_filters as filters
from .forms import ProfileCreateForm, ProfileEditForm, OpportunityForm, IntroRequestForm
from admin_frontend.templatetags.public_urls import public_route
from api.services.matching import rank_users_for, rank_opportunities_for
from api.services.benefit import build_leaderboard_queryset
from .nav import _nav_items
from orgs.models import OrganizationSite


class SiteLoginView(LoginView):
    """Login view that redirects users to their organization's Site domain.

    After successful authentication, it looks up the user's organization via
    `user.recycle_profile.organization`, maps it to a `Site` domain via
    `OrganizationSite`, and returns an absolute URL to `/webadmin/` on that domain.
    Falls back to the default behavior if mapping is missing.
    """

    def get_success_url(self):
        url = super().get_success_url()
        try:
            user = self.request.user
            org = getattr(getattr(user, "recycle_profile", None), "organization", None)
            if org is None:
                return url
            mapping = OrganizationSite.objects.select_related("site").filter(organization=org).first()
            if not mapping or not mapping.site:
                return url

            domain = mapping.site.domain
            scheme = "https" if self.request.is_secure() else "http"
            host_header = self.request.get_host() or ""
            current_port = ""
            # Preserve incoming port from Host header if present (e.g., 8024 in Docker)
            if ":" in host_header:
                try:
                    current_port = host_header.rsplit(":", 1)[1]
                except Exception:
                    current_port = ""

            if current_port and not (
                (scheme == "http" and current_port == "80") or (scheme == "https" and current_port == "443")
            ):
                netloc = f"{domain}:{current_port}"
            else:
                netloc = domain

            return f"{scheme}://{netloc}/webadmin/"
        except Exception:
            return url



@staff_member_required
@public_route(label="Dashboard", order=10, icon="home")
def dashboard(request):
    context = {
        "nav": _nav_items(),
        "counts": {
            "profiles": Profile.objects.count(),
            "opportunities": Opportunity.objects.count(),
            "intro_requests": IntroductionRequest.objects.count(),
        },
    }
    return render(request, "admin_frontend/dashboard.html", context)


@staff_member_required
@public_route(label="Profiles", order=20, icon="users")
def profiles_list(request):
    # django-filter FilterSet for profiles
    class ProfileFilter(filters.FilterSet):
        username = filters.CharFilter(field_name="user__username", lookup_expr="icontains", label="Username")
        industry = filters.CharFilter(field_name="industry", lookup_expr="icontains", label="Industry")
        is_verified = filters.BooleanFilter(field_name="is_verified", label="Verified")
        tag = filters.CharFilter(field_name="tags__name", lookup_expr="icontains", label="Tag")

        class Meta:
            model = Profile
            fields = ["username", "industry", "is_verified", "tag"]

        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            try:
                from crispy_forms.helper import FormHelper
                from crispy_forms.layout import Layout, Field
                helper = FormHelper()
                helper.form_tag = False
                helper.layout = Layout(
                    Field("username", template="crispy/field_nowrap.html"),
                    Field("industry", template="crispy/field_nowrap.html"),
                    Field("tag", template="crispy/field_nowrap.html"),
                    Field("is_verified", template="crispy/field_nowrap.html"),
                )
                self.form.helper = helper
            except Exception:
                # If crispy is unavailable for any reason, fail silently
                pass

    qs = Profile.objects.select_related("user").all().order_by("-id")

    prof_filter = ProfileFilter(request.GET, queryset=qs)
    paginator = Paginator(prof_filter.qs, 10)
    page = request.GET.get("page")
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        page_obj = paginator.page(1)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)

    context = {"nav": _nav_items(), "profiles": page_obj.object_list, "page_obj": page_obj, "filter": prof_filter}
    return render(request, "admin_frontend/profiles_list.html", context)


@staff_member_required
@require_POST
def profile_toggle_verify(request, pk: int):
    profile = get_object_or_404(Profile, pk=pk)
    profile.is_verified = not profile.is_verified
    profile.save(update_fields=["is_verified"])
    messages.success(request, f"Profile '{profile.user.username}' verification toggled.")
    return redirect(request.META.get("HTTP_REFERER") or reverse("admin_frontend:profiles_list"))


@staff_member_required
@public_route(label="Opportunities", order=30, icon="briefcase")
def opportunities_list(request):
    if request.method == "POST":
        form = OpportunityForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Opportunity created.")
            return redirect("admin_frontend:opportunities_list")
        else:
            messages.error(request, "Please correct the errors below.")
    else:
        form = OpportunityForm()

    # django-filter FilterSet for opportunities
    class OpportunityFilter(filters.FilterSet):
        title = filters.CharFilter(field_name="title", lookup_expr="icontains", label="Title")
        created_at = filters.DateTimeFromToRangeFilter(
            field_name="created_at",
            label="Created between",
            widget=filters.widgets.RangeWidget(
                attrs={
                    "type": "datetime-local",
                    "style": "color-scheme: light;",
                    "class": "border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500",
                }
            ),
        )

        class Meta:
            model = Opportunity
            fields = ["title", "created_at"]

    opp_qs = Opportunity.objects.order_by("-created_at")
    opp_filter = OpportunityFilter(request.GET, queryset=opp_qs)
    paginator = Paginator(opp_qs, 10)
    page = request.GET.get("page")
    try:
        page_obj = Paginator(opp_filter.qs, 10).page(page)
    except PageNotAnInteger:
        page_obj = Paginator(opp_filter.qs, 10).page(1)
    except EmptyPage:
        # using paginator over filtered qs to get total pages
        filtered_paginator = Paginator(opp_filter.qs, 10)
        page_obj = filtered_paginator.page(filtered_paginator.num_pages)

    context = {
        "nav": _nav_items(),
        "opportunities": page_obj.object_list,
        "page_obj": page_obj,
        "form": form,
        "filter": opp_filter,
    }
    return render(request, "admin_frontend/opportunities_list.html", context)


@staff_member_required
@public_route(label="Intro Requests", order=40, icon="arrows-right-left")
def introduction_requests_list(request):
    items = IntroductionRequest.objects.select_related("from_user", "to_user").order_by("-created_at")

    paginator = Paginator(items, 10)
    page = request.GET.get("page")
    try:
        page_obj = paginator.page(page)
    except PageNotAnInteger:
        page_obj = paginator.page(1)
    except EmptyPage:
        page_obj = paginator.page(paginator.num_pages)

    context = {"nav": _nav_items(), "requests": page_obj.object_list, "page_obj": page_obj}
    return render(request, "admin_frontend/intro_requests_list.html", context)


@staff_member_required
@public_route(label="Leaderboard", order=25, icon="trophy")
def leaderboard(request):
    period = (request.GET.get("period") or "weekly").lower()
    try:
        limit = min(max(int(request.GET.get("limit", 25)), 1), 200)
    except Exception:
        limit = 25
    try:
        offset = max(int(request.GET.get("offset", 0)), 0)
    except Exception:
        offset = 0

    try:
        qs = build_leaderboard_queryset(period)
        rows = list(qs[offset : offset + limit])
        me = qs.filter(id=request.user.id).first()
    except Exception:
        rows = []
        me = None

    context = {
        "nav": _nav_items(),
        "period": period,
        "limit": limit,
        "offset": offset,
        "rows": rows,
        "me": me,
        "limit_options": [10, 25, 50, 100],
    }
    return render(request, "admin_frontend/leaderboard.html", context)


@staff_member_required
@require_POST
def intro_request_accept(request, pk: int):
    item = get_object_or_404(IntroductionRequest, pk=pk)
    if not item.is_accepted:
        item.is_accepted = True
        item.save(update_fields=["is_accepted"])
        messages.success(request, "Introduction request accepted.")
    else:
        messages.info(request, "Already accepted.")
    return redirect(request.META.get("HTTP_REFERER") or reverse("admin_frontend:intro_requests_list"))


@staff_member_required
def opportunity_edit(request, pk: int):
    opp = get_object_or_404(Opportunity, pk=pk)
    if request.method == "POST":
        form = OpportunityForm(request.POST, instance=opp)
        if form.is_valid():
            form.save()
            messages.success(request, "Opportunity updated.")
            return redirect("admin_frontend:opportunity_edit", pk=opp.pk)
    else:
        form = OpportunityForm(instance=opp)

    context = {"nav": _nav_items(), "opportunity": opp, "form": form, "cancel_url": reverse("admin_frontend:opportunities_list")}
    return render(request, "admin_frontend/opportunity_form.html", context)


@staff_member_required
@require_POST
def opportunity_delete(request, pk: int):
    opp = get_object_or_404(Opportunity, pk=pk)
    opp.delete()
    messages.success(request, "Opportunity deleted.")
    return redirect("admin_frontend:opportunities_list")


# Profiles CRUD

@staff_member_required
def profile_create(request):
    if request.method == "POST":
        form = ProfileCreateForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Profile created.")
            return redirect("admin_frontend:profiles_list")
    else:
        form = ProfileCreateForm()

    return render(
        request,
        "admin_frontend/profile_form.html",
        {"nav": _nav_items(), "creating": True, "form": form, "cancel_url": reverse("admin_frontend:profiles_list")},
    )


@staff_member_required
def profile_edit(request, pk: int):
    profile = get_object_or_404(Profile, pk=pk)
    if request.method == "POST":
        form = ProfileEditForm(request.POST, instance=profile)
        if form.is_valid():
            form.save()
            messages.success(request, "Profile updated.")
            return redirect("admin_frontend:profile_edit", pk=profile.pk)
    else:
        form = ProfileEditForm(instance=profile)

    # Suggestions for this user (top 5)
    try:
        user_matches = rank_users_for(profile.user, k=5)
    except Exception:
        user_matches = []
    try:
        opp_recs = rank_opportunities_for(profile.user, k=5)
    except Exception:
        opp_recs = []

    return render(
        request,
        "admin_frontend/profile_form.html",
        {
            "nav": _nav_items(),
            "profile": profile,
            "creating": False,
            "form": form,
            "cancel_url": reverse("admin_frontend:profiles_list"),
            "user_matches": user_matches,
            "opp_recs": opp_recs,
        },
    )


@staff_member_required
@require_POST
def profile_delete(request, pk: int):
    profile = get_object_or_404(Profile, pk=pk)
    profile.delete()
    messages.success(request, "Profile deleted.")
    return redirect("admin_frontend:profiles_list")


# Intro Requests CRUD

@staff_member_required
def intro_request_create(request):
    if request.method == "POST":
        form = IntroRequestForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, "Introduction request created.")
            return redirect("admin_frontend:intro_requests_list")
    else:
        form = IntroRequestForm()

    return render(
        request,
        "admin_frontend/intro_request_form.html",
        {"nav": _nav_items(), "creating": True, "form": form, "cancel_url": reverse("admin_frontend:intro_requests_list")},
    )


@staff_member_required
def intro_request_edit(request, pk: int):
    item = get_object_or_404(IntroductionRequest, pk=pk)
    if request.method == "POST":
        form = IntroRequestForm(request.POST, instance=item)
        if form.is_valid():
            form.save(instance=item)
            messages.success(request, "Introduction request updated.")
            return redirect("admin_frontend:intro_request_edit", pk=item.pk)
    else:
        form = IntroRequestForm(instance=item)

    context = {"nav": _nav_items(), "item": item, "creating": False, "form": form, "cancel_url": reverse("admin_frontend:intro_requests_list")}
    return render(request, "admin_frontend/intro_request_form.html", context)


@staff_member_required
@require_POST
def intro_request_delete(request, pk: int):
    item = get_object_or_404(IntroductionRequest, pk=pk)
    item.delete()
    messages.success(request, "Introduction request deleted.")
    return redirect("admin_frontend:intro_requests_list")


## Recycle Core admin UI moved to recycle_core app
