from __future__ import annotations

from django.shortcuts import render, redirect
from django.contrib import messages
from django.urls import reverse
from django.views.decorators.http import require_POST
from django.contrib.auth.models import Group, Permission
from django.contrib.auth import get_user_model
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.db import models

from .models import Organization, OrganizationSite, UserProfile
from .forms import OrganizationForm

from admin_frontend.templatetags.public_urls import public_route
from cms.views import breadcrumbs


def _owner_required(request):
    profile = getattr(request.user, "recycle_profile", None)
    return bool(profile and profile.role == "owner" and (getattr(request, "org", None) is None or profile.organization_id == request.org.id))


@public_route(label="Organization Settings", order=10, icon="cog-6-tooth")
@breadcrumbs(label="Organization Settings", name="org_settings")
def org_settings(request):
    if not request.user.is_authenticated or not _owner_required(request):
        messages.error(request, "Only organization owners can access organization settings.")
        return redirect("admin_frontend:dashboard")

    org = getattr(request, "org", None)
    if not org:
        messages.error(request, "Organization context missing.")
        return redirect("admin_frontend:dashboard")

    if request.method == "POST":
        form = OrganizationForm(request.POST, instance=org)
        if form.is_valid():
            form.save()
            messages.success(request, "Organization updated.")
            return redirect("orgs_admin:org_settings")
        messages.error(request, "Please correct the errors below.")
    else:
        form = OrganizationForm(instance=org)

    return render(request, "orgs/org_settings.html", {"form": form})


@public_route(label="Organization Sites", order=12, icon="link")
@breadcrumbs(label="Organization Sites", name="org_sites")
def org_sites(request):
    if not request.user.is_authenticated or not _owner_required(request):
        messages.error(request, "Only organization owners can access organization sites.")
        return redirect("admin_frontend:dashboard")

    org = getattr(request, "org", None)
    mappings = OrganizationSite.objects.select_related("site").filter(organization=org)

    if request.method == "POST":
        # Simple action: ensure current request.site is mapped to this org
        cur_site = getattr(request, "site", None)
        if not cur_site:
            messages.error(request, "Current site not detected.")
            return redirect("orgs_admin:org_sites")
        mapping, created = OrganizationSite.objects.get_or_create(site=cur_site, defaults={"organization": org})
        if not created and mapping.organization_id != org.id:
            messages.error(request, "This site is already mapped to another organization.")
        else:
            messages.success(request, "Current site mapped to this organization.")
        return redirect("orgs_admin:org_sites")

    return render(request, "orgs/org_sites.html", {"mappings": mappings, "current_site": getattr(request, "site", None)})


## ProvidedService management moved to recycle_core views


# Permissions management ------------------------------------------------------


ROLE_GROUPS = ["owner", "manager", "driver", "customer", "auditor"]
APP_WHITELIST = {"recycle_core", "billing", "orgs"}


@public_route(label="Permissions", order=14, icon="key")
@breadcrumbs(label="Permissions", name="org_permissions")
def permissions_overview(request):
    if not request.user.is_authenticated or not _owner_required(request):
        messages.error(request, "Only organization owners can manage permissions.")
        return redirect("admin_frontend:dashboard")

    groups = list(Group.objects.filter(name__in=ROLE_GROUPS).order_by("name"))
    # Ensure missing role groups are visible
    existing = {g.name for g in groups}
    for name in ROLE_GROUPS:
        if name not in existing:
            g = Group.objects.create(name=name)
            groups.append(g)
    groups.sort(key=lambda g: ROLE_GROUPS.index(g.name) if g.name in ROLE_GROUPS else 999)

    return render(request, "orgs/permissions_list.html", {"groups": groups})


@breadcrumbs(label="Edit Group Permissions", parent="org_permissions")
def permissions_edit_group(request, pk: int):
    if not request.user.is_authenticated or not _owner_required(request):
        messages.error(request, "Only organization owners can manage permissions.")
        return redirect("admin_frontend:dashboard")

    group = Group.objects.filter(pk=pk).first()
    if not group:
        messages.error(request, "Group not found.")
        return redirect("orgs_admin:permissions_overview")

    # Only allow editing for known role groups to avoid unexpected global changes
    if group.name not in ROLE_GROUPS:
        messages.error(request, "Only role groups can be edited here.")
        return redirect("orgs_admin:permissions_overview")

    perms_all = Permission.objects.select_related("content_type").all()
    perms_all = [p for p in perms_all if p.content_type.app_label in APP_WHITELIST]

    # Build structured grouping: app -> [ {model_key, model_label, perms:[...]}, ... ]
    grouped_apps = {}

    def perm_order_key(codename: str) -> tuple[int, str]:
        # Standard Django perms first in this order, then custom alphabetically
        prefix_order = {"view": 0, "add": 1, "change": 2, "delete": 3}
        prefix = codename.split("_", 1)[0] if "_" in codename else codename
        return (prefix_order.get(prefix, 9), codename)

    def model_sort_key(app_label: str, model_key: str, model_label: str) -> tuple[int, str]:
        if app_label == "billing":
            pref = {"invoice": 0, "invoiceline": 1, "payment": 2, "payout": 3}
            return (pref.get(model_key, 9), model_label)
        return (0, model_label)

    for p in perms_all:
        app = p.content_type.app_label
        model_key = p.content_type.model  # e.g., 'invoice', 'invoiceline'
        # Use content_type.name for human label (e.g., 'invoice line')
        model_label = p.content_type.name.title()
        app_bucket = grouped_apps.setdefault(app, {})
        bucket = app_bucket.setdefault(model_key, {"model_key": model_key, "model_label": model_label, "perms": []})
        bucket["perms"].append(p)

    # Convert inner dicts to sorted lists
    for app, models_map in list(grouped_apps.items()):
        models_list = list(models_map.values())
        # Sort perms within model
        for m in models_list:
            m["perms"].sort(key=lambda pr: perm_order_key(pr.codename))
        # Sort models by preference
        models_list.sort(key=lambda m: model_sort_key(app, m["model_key"], m["model_label"]))
        grouped_apps[app] = models_list

    if request.method == "POST":
        sel_ids = request.POST.getlist("perm_ids")
        try:
            sel_ids = [int(x) for x in sel_ids]
        except Exception:
            sel_ids = []
        # Only set within whitelist
        allowed_ids = {p.id for p in perms_all}
        final_ids = [pid for pid in sel_ids if pid in allowed_ids]
        group.permissions.set(Permission.objects.filter(id__in=final_ids))
        messages.success(request, f"Permissions updated for group '{group.name}'.")
        # Redirect back to the current URL (stay on the edit page)
        return redirect(request.get_full_path())

    current_ids = set(group.permissions.values_list("id", flat=True))

    return render(
        request,
        "orgs/permissions_edit.html",
        {"group": group, "grouped_apps": grouped_apps, "current_ids": current_ids},
    )


@breadcrumbs(label="Group Users", parent="org_permissions")
def permissions_group_users(request, pk: int):
    if not request.user.is_authenticated or not _owner_required(request):
        messages.error(request, "Only organization owners can view group users.")
        return redirect("admin_frontend:dashboard")

    group = Group.objects.filter(pk=pk).first()
    if not group:
        messages.error(request, "Group not found.")
        return redirect("orgs_admin:permissions_overview")

    User = get_user_model()
    qs = User.objects.filter(groups=group).order_by("username")
    # Scope to current organization if present
    org = getattr(request, "org", None)
    if org is not None:
        qs = qs.filter(recycle_profile__organization=org)

    # Filters
    q = (request.GET.get("q") or "").strip()
    role = (request.GET.get("role") or "").strip()
    if q:
        qs = qs.filter(models.Q(username__icontains=q) | models.Q(email__icontains=q))
    if role:
        qs = qs.filter(recycle_profile__role=role)

    qs = qs.select_related("recycle_profile", "recycle_profile__organization")

    # Pagination
    paginator = Paginator(qs, 15)
    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)

    role_choices = list(UserProfile.ROLE_CHOICES)

    return render(
        request,
        "orgs/permissions_group_users.html",
        {"group": group, "users": page_obj.object_list, "page_obj": page_obj, "q": q, "role": role, "role_choices": role_choices},
    )
