from django.urls import reverse
from urllib.parse import parse_qsl, urlsplit
from . import queries as q


def _listing(kind):
    return q.KINDS[kind][0], reverse("operations:list", args=[kind]), q.KINDS[kind][1], kind == "customers"


def _report_sections():
    from apps.reporting.views import REPORTS
    return [(label, reverse("reporting:section", args=[key]), permission, False)
            for key, (label, permission, _) in REPORTS.items()]


def navigation():
    """Every navigation group the shell can show, as (label, title, url, permission, company_only).

    This is the shell's declaration of what it needs. It carries no authorization
    logic: each entry states the capability a link requires, and the shell renders
    a link only when the authoritative resolver grants that capability.
    """
    from apps.configuration.navigation import configuration_links
    return [
        ("Operations", [
            ("Appointments", reverse("frontdesk:index"), "frontdesk.view_appointment", False),
            ("Walk-in queue", reverse("frontdesk:index"), "frontdesk.view_queue", False),
            _listing("cases"),
            ("Engineer work", reverse("operations:list", args=["cases"])+"?bucket=mine", "service.handle_servicecase", False),
            ("Quality control", reverse("operations:list", args=["cases"])+"?bucket=qc", "service.perform_quality_control", False),
            _listing("customers"), _listing("devices")]),
        ("Parts & inventory", [
            ("Inventory overview", reverse("operations:inventory_workspace", args=["overview"]), "inventory.view_stock", False),
            ("Receiving", reverse("operations:inventory_workspace", args=["receipts"]), "inventory.view_stock", False),
            ("Positions", reverse("operations:inventory_workspace", args=["positions"]), "inventory.view_stock", False),
            ("Transfers", reverse("operations:inventory_workspace", args=["transfers"]), "inventory.view_stock", False),
            ("Counts / adjustments", reverse("operations:inventory_workspace", args=["counts"]), "inventory.view_stock", False),
            ("Inventory history", reverse("operations:inventory_workspace", args=["history"]), "inventory.view_stock", False),
            ("Parts requests", reverse("operations:inventory_workspace", args=["requests"]), "inventory.view_stock", False),
            _listing("parts"), _listing("inventory")]),
        ("Commercial", [(label, reverse("operations:commercial_workspace", args=[kind]), permission, False)
            for kind, label, permission in (
                ("quotations", "Quotations", "commercial.view_servicequotation"),
                ("invoices", "Invoices", "commercial.view_serviceinvoice"),
                ("payments", "Payments", "commercial.view_servicepayment"),
                ("outstanding", "Outstanding", "commercial.view_servicepayment"),
                ("receipts", "Receipts", "commercial.view_servicepayment"),
                ("releases", "Due-release history", "commercial.view_servicepayment"))]),
        ("Monitoring", [
            ("SLA monitoring", reverse("sla:dashboard"), "sla.view_sla", False),
            ("Communication history", reverse("communications:history"), "communications.view_notification", False),
            ("Queue customer message", reverse("communications:manual"), "communications.send_notification", True),
            ("Templates", reverse("communications:templates"), "communications.manage_templates", True)] + _report_sections()),
        ("System", configuration_links()[1]),
    ]


def capability_questions():
    """Distinct capability questions the shell asks, split by company-only scope."""
    from apps.configuration.navigation import CONFIGURATION_CAPABILITIES
    questions = {False: set(), True: set()}
    for _, entries in navigation():
        for _title, _url, permission, company_only in entries:
            questions[company_only].add(permission)
    for permission, company_only in CONFIGURATION_CAPABILITIES.items():
        questions[company_only].add(permission)
    return questions


def shell(request):
    if hasattr(request, "_operation_shell"):
        return request._operation_shell
    # Error handlers may render before AuthenticationMiddleware attaches a user.
    user = getattr(request, "user", None)
    if request.path.startswith("/admin/") or user is None or not user.is_authenticated or not user.is_active:
        return {"workspace": None}
    # One authoritative bulk resolution for every question above, both scope modes.
    questions = capability_questions()
    asked = {(permission, mode) for mode in (False, True) for permission in questions[mode]}
    capabilities = {key: allowed for key, allowed in q.capability_map(
        request.user, sorted(questions[False] | questions[True])).items() if key in asked}

    def can(permission, company_only=False):
        return capabilities.get((permission, company_only), False)

    groups = []
    for label, entries in navigation():
        links = [{"label": title, "url": url} for title, url, permission, company_only in entries
                 if can(permission, company_only)
                 and ("?bucket=" not in url or can("service.view_servicecase"))]
        if links:
            if label == "Commercial":
                links.insert(0, {"label": "Commercial overview", "url": reverse("operations:commercial_workspace", args=["overview"])})
            groups.append({"label": label, "links": links})
    from apps.configuration.navigation import visible
    if visible(request, can):
        system = next((group for group in groups if group["label"] == "System"), None)
        if system is None:
            system = {"label": "System", "links": []}
            groups.append(system)
        system["links"].append({"label": "Administration / Settings (Configuration center)", "url": reverse("configuration:index")})
    # The existing Admin contains global master-data screens. Do not advertise
    # unrestricted Admin browsing as a scoped operational permission.
    if request.user.is_superuser and request.user.is_staff:
        system["links"].append({"label": "Django Admin", "url": reverse("admin:index")})
    # Presentation only: prefer the selected queue over its generic case list.
    matching = []
    for group in groups:
        for link in group["links"]:
            destination = urlsplit(link["url"])
            parameters = parse_qsl(destination.query)
            if request.path == destination.path and all(request.GET.get(key) == value for key, value in parameters):
                matching.append((len(parameters), link))
    if matching:
        max(matching, key=lambda match: match[0])[1]["current"] = True
    request._operation_shell = {"workspace": {"groups": groups, "capabilities": capabilities,
        "context": "All authorized scopes · each module applies its own permissions"}}
    return request._operation_shell
