"""On-demand, read-only job evidence. No transition or stock calculations."""
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.db.models import Exists, OuterRef
from django.http import Http404
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views.decorators.cache import never_cache
from django.views.decorators.http import require_GET

from apps.organization.models import ServiceCenter
from apps.service import diagnostic_queries as diagnosis, repair_queries as repair, quality_control_queries as qc
from apps.service import engineer_queries, handover_queries
from apps.commercial import queries as quotations, invoice_queries, payment_queries
from apps.inventory import request_queries, usage_queries
from . import queries


PERMISSIONS = {
    "engineer": "service.handle_servicecase", "supervisor": "service.change_servicecase",
    "parts": "inventory.view_stock", "quote": "commercial.view_servicequotation",
    "invoice": "commercial.view_serviceinvoice", "payment": "commercial.view_servicepayment",
}
LABELS = {"overview": "Overview", "diagnosis": "Complaint & diagnosis", "repair": "Repair",
          "parts": "Parts", "commercial": "Commercial", "qc": "Quality control",
          "delivery": "Delivery", "history": "History"}


def access(actor, case):
    """One SQL read, each permission resolved against this exact center."""
    flags = ServiceCenter.objects.filter(pk=case.service_center_id).annotate(**{
        key: Exists(queries.centers(actor, permission).filter(pk=OuterRef("pk")))
        for key, permission in PERMISSIONS.items()
    }).values(*PERMISSIONS).first() or dict.fromkeys(PERMISSIONS, False)
    flags["technical"] = flags["engineer"] or flags["supervisor"]
    return flags


def sections(case, flags, qc_visible):
    allowed = {"overview", "diagnosis", "delivery", "history"}
    if flags["technical"]:
        allowed.add("repair")
    if flags["parts"]:
        allowed.add("parts")
    if any(flags[key] for key in ("quote", "invoice", "payment")):
        allowed.add("commercial")
    if qc_visible:
        allowed.add("qc")
    return [dict(key=key, label=label, url=reverse("operations:detail", args=["cases", case.pk]) if key == "overview"
                 else reverse("operations:job_section", args=[case.pk, key])) for key, label in LABELS.items() if key in allowed]


def evidence(actor, case, section, flags, qc_visible):
    """Explicit field allowlists, at most ten records per source (50 child rows)."""
    groups = []
    def group(title, rows):
        groups.append(dict(title=title, rows=rows))
    if section in ("diagnosis", "history"):
        group("Intake remarks", [[("Reported at intake", case.intake_note or "Not recorded")]])
        group("Reported complaints", [[("Symptom", row.complaint_symptom.name), ("Reported observation", row.customer_description),
            ("Removed", row.removed_at)] for row in case.complaints.select_related("complaint_symptom").order_by("pk")[:10]])
    if section in ("diagnosis", "history") and flags["technical"]:
        rows = list(diagnosis.diagnostic_assessment_history(case).order_by("-started_at", "-pk")[:10])
        group("Diagnostic assessments", [[("Started", row.started_at), ("Completed", row.completed_at),
            ("Abandoned", row.abandoned_at), ("Engineer", row.engineer_assignment.engineer.get_username()),
            ("Technical observations", row.technical_note)] for row in rows])
        from apps.service.models import ServiceDiagnosticFinding
        findings = ServiceDiagnosticFinding.objects.filter(assessment__in=rows).select_related("assessment", "fault_diagnosis", "root_cause").order_by("-assessment__started_at", "pk")[:50]
        group("Diagnostic findings", [[("Assessment started", row.assessment.started_at), ("Fault diagnosis", row.fault_diagnosis.name),
            ("Root cause", row.root_cause.name if row.root_cause else "Unknown / Unconfirmed"), ("Note", row.note)] for row in findings])
    if section in ("repair", "history") and flags["technical"]:
        rows = list(repair.repair_execution_history(case).order_by("-started_at", "-pk")[:10])
        group("Repair executions", [[("Started", row.started_at), ("Status", row.status), ("Outcome", row.outcome),
            ("Completed", row.completed_at), ("Abandoned", row.abandoned_at), ("Technician notes", row.note)] for row in rows])
        from apps.service.models import ServiceRepairAction
        actions = ServiceRepairAction.objects.filter(repair_execution__in=rows).select_related("repair_execution", "repair_action").order_by("-repair_execution__started_at", "pk")[:50]
        group("Repair actions", [[("Execution started", row.repair_execution.started_at), ("Action", row.repair_action.name),
            ("Active", row.is_active), ("Performed", row.performed_at), ("Note", row.note)] for row in actions])
    if section in ("parts", "history") and flags["parts"]:
        rows = list(request_queries.parts_requests(actor=actor).filter(service_case=case).order_by("-requested_at", "-pk")[:10])
        group("Parts requests", [[("Request", row.pk), ("Requested", row.requested_at), ("Status", row.status)] for row in rows])
        from apps.inventory.models import PartsRequestLine
        group("Requested quantities", [[("Request", row.request_id), ("Part", row.spare_part.part_code), ("Quantity", row.quantity)]
            for row in PartsRequestLine.objects.filter(request__in=rows).select_related("spare_part").order_by("pk")[:50]])
        group("Reservations", [[("Reserved", row.reserved_at), ("Part", row.spare_part.part_code), ("Quantity", row.quantity),
            ("Location", row.location.code), ("Status", row.status)] for row in request_queries.stock_reservations(actor=actor).filter(service_case=case).order_by("-reserved_at", "pk")[:10]])
        group("Issued parts", [[("Issued", row.issued_at), ("Part", row.reservation.spare_part.part_code),
            ("Quantity", row.reservation.quantity), ("Custodian", row.recipient.get_username()), ("Resolved quantity", row.resolved_quantity)]
            for row in usage_queries.parts_issues(actor=actor).filter(service_case=case).order_by("-issued_at", "pk")[:10]])
        group("Consumed / unused returned", [[("Recorded", row.recorded_at), ("Part", row.issue.reservation.spare_part.part_code),
            ("Disposition", row.get_kind_display()), ("Quantity", row.quantity)] for row in usage_queries.parts_usage(actor=actor).filter(issue__service_case=case).order_by("-recorded_at", "pk")[:10]])
        group("Defective recoveries", [[("Recovered", row.recovered_at), ("Component", row.component_description),
            ("Quantity", row.quantity), ("Location", row.location.code)] for row in usage_queries.defective_recoveries(actor=actor).filter(service_case=case).order_by("-recovered_at", "pk")[:10]])
    if section in ("commercial", "history"):
        if flags["quote"]:
            group("Quotation revisions", [[("Quotation", row.family.number), ("Revision", row.revision), ("Current", row.is_current),
                ("Status", row.status), ("Customer decision", getattr(getattr(row, "decision", None), "outcome", "Not recorded")),
                ("Decision recorded", getattr(getattr(row, "decision", None), "created_at", None)),
                ("Currency", row.currency), ("Quotation value", row.grand_total),
                ("Created", row.created_at), ("Submitted", row.submitted_at)] for row in quotations.service_quotations(actor=actor).filter(family__service_case=case).order_by("-revision")[:10]])
        if flags["invoice"]:
            group("Invoices", [[("Invoice", row.number), ("Status", row.status), ("Currency", row.currency),
                ("Invoice value (not revenue)", row.grand_total), ("Created", row.created_at)]
                for row in invoice_queries.service_invoices(actor=actor).filter(service_case=case)[:10]])
    if section in ("commercial", "delivery", "history") and flags["payment"]:
        group("Financial clearance", [[("Invoice", row.number), ("Currency", row.currency), ("Customer liability", row.customer_pay_total),
            ("Paid", row.paid_amount), ("Outstanding balance", row.balance_due),
            ("Clearance", "No outstanding customer balance" if row.balance_due == 0 else "Authorized due-release; balance remains due" if row.release_limit >= row.balance_due else "Outstanding customer balance; no sufficient due-release")]
            for row in payment_queries.settlement_invoices(actor=actor).filter(service_case=case)[:10]])
        if section != "delivery":
            group("Payments", [[("Received", row.received_at), ("Status", row.status), ("Currency", row.currency), ("Amount", row.amount)]
                for row in payment_queries.service_payments(actor=actor).filter(invoice__service_case=case).order_by("-received_at", "pk")[:10]])
    if section in ("qc", "history") and qc_visible:
        rows = list(qc.quality_control_history(case).order_by("-started_at", "-pk")[:10])
        group("QC attempts", [[("Started", row.started_at), ("Status", row.status), ("Outcome", row.outcome), ("Completed", row.completed_at),
            ("Inspector", row.inspector.get_username()), ("Summary", row.summary), ("Failure note", row.failure_note)] for row in rows])
        from apps.service.models import ServiceQualityControlCheck, ServiceQualityControlComplaintCheck
        group("QC technical checks", [[("QC started", row.quality_control.started_at), ("Check", row.check_name), ("Result", row.result), ("Note", row.note)]
            for row in ServiceQualityControlCheck.objects.filter(quality_control__in=rows).select_related("quality_control").order_by("-quality_control__started_at", "sequence", "pk")[:50]])
        group("QC complaint checks", [[("QC started", row.quality_control.started_at), ("Complaint", row.complaint.complaint_symptom.name), ("Result", row.result), ("Note", row.note)]
            for row in ServiceQualityControlComplaintCheck.objects.filter(quality_control__in=rows).select_related("quality_control", "complaint__complaint_symptom").order_by("-quality_control__started_at", "pk")[:50]])
    if section in ("delivery", "history"):
        group("Delivery evidence", [[("Ready", getattr(handover_queries.get_service_case_delivery_release(case), "readied_at", None)),
            ("Handed over", getattr(handover_queries.get_service_case_handover(case), "delivered_at", None)),
            ("Closed", getattr(handover_queries.get_service_case_closure(case), "closed_at", None))]])
    if section == "history":
        group("Intake", [[("Received", case.received_at), ("Current status", case.get_status_display())]])
        group("Assignment history", [[("Assigned", row.assigned_at), ("Engineer", row.engineer.get_username()),
            ("Ended", row.ended_at)] for row in engineer_queries.engineer_assignment_history(case).order_by("-assigned_at", "-pk")[:10]])
    return groups


@never_cache
@login_required(login_url="operations:login")
@require_GET
def section(request, pk, section):
    if section not in LABELS or section == "overview":
        raise Http404
    case = get_object_or_404(queries.cases(request.user), pk=pk)
    flags = access(request.user, case)
    qc_visible = qc.quality_control_visible_cases(request.user).filter(pk=case.pk).exists()
    navigation = sections(case, flags, qc_visible)
    if section not in {item["key"] for item in navigation}:
        raise PermissionDenied
    return render(request, "operations/job_section.html", dict(title=f"{case.job_number} · {LABELS[section]}", case=case,
        section=section, sections=navigation, commercial_access=flags,
        groups=evidence(request.user, case, section, flags, qc_visible)))
