from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.translation import gettext as _
from django.views.decorators.http import require_http_methods

from apps.core.services import AuditService
from apps.organizations.models import Staff

from .models import Complaint, ComplaintExplanation, ComplaintStatus
from .services.complaint_service import ComplaintService, ComplaintServiceError


@login_required
@require_http_methods(["GET", "POST"])
def send_to_department_form(request, pk):
    complaint = get_object_or_404(
        Complaint.objects.prefetch_related(
            "involved_staff__staff__department",
            "involved_staff__staff__report_to",
            "involved_departments__department__champion",
            "involved_departments__department__manager",
        ),
        pk=pk,
    )

    user = request.user
    can_request = (
        user.is_px_admin()
        or user.is_hospital_admin()
        or (user.is_department_manager() and complaint.department == user.department)
        or (complaint.hospital == user.hospital)
    )

    if not can_request:
        return HttpResponseForbidden(_("You don't have permission to request explanations."))

    if not complaint.is_active_status:
        messages.error(
            request,
            _(
                "Cannot request explanation for complaint with status '{}'. Complaint must be Open, In Progress, or Partially Resolved."
            ).format(complaint.get_status_display()),
        )
        return redirect("complaints:complaint_detail", pk=complaint.pk)

    involved_staff = complaint.involved_staff.select_related(
        "staff", "staff__department", "staff__report_to"
    ).all()

    department_groups = {}
    ungrouped_staff = []

    # Build department groups from involved_departments first
    involved_departments = complaint.involved_departments.select_related(
        "department__champion", "department__manager"
    ).all()

    for dept_inv in involved_departments:
        dept = dept_inv.department
        if not dept:
            continue

        dept_key = str(dept.id)
        if dept_key not in department_groups:
            champion = dept.champion
            champion_email = champion.email or (champion.user.email if champion and champion.user else None) if champion else None
            dept_manager = dept.manager
            department_groups[dept_key] = {
                "department_id": dept_key,
                "department_name": dept.get_localized_name(),
                "champion": champion,
                "champion_id": str(champion.id) if champion else None,
                "champion_name": champion.get_full_name() if champion else None,
                "champion_email": champion_email,
                "dept_manager": dept_manager,
                "dept_manager_id": str(dept_manager.id) if dept_manager else None,
                "dept_manager_name": dept_manager.get_full_name() if dept_manager else None,
                "dept_manager_email": dept_manager.email if dept_manager else None,
                "staff_list": [],
            }

    # Add involved staff to their department groups
    for staff_inv in involved_staff:
        staff = staff_inv.staff
        dept = staff.department
        entry = {
            "staff_inv": staff_inv,
            "staff": staff,
            "staff_id": str(staff.id),
            "staff_name": staff.get_full_name(),
            "staff_email": staff.email or (staff.user.email if staff.user else None),
            "role": staff_inv.get_role_display(),
        }

        if dept:
            dept_key = str(dept.id)
            if dept_key in department_groups:
                department_groups[dept_key]["staff_list"].append(entry)
            else:
                champion = dept.champion
                champion_email = champion.email or (champion.user.email if champion and champion.user else None) if champion else None
                dept_manager = dept.manager
                department_groups[dept_key] = {
                    "department_id": dept_key,
                    "department_name": dept.get_localized_name(),
                    "champion": champion,
                    "champion_id": str(champion.id) if champion else None,
                    "champion_name": champion.get_full_name() if champion else None,
                    "champion_email": champion_email,
                    "dept_manager": dept_manager,
                    "dept_manager_id": str(dept_manager.id) if dept_manager else None,
                    "dept_manager_name": dept_manager.get_full_name() if dept_manager else None,
                    "dept_manager_email": dept_manager.email if dept_manager else None,
                    "staff_list": [entry],
                }
        else:
            ungrouped_staff.append(entry)

    if not department_groups and not involved_staff.exists():
        if not involved_departments.exists():
            messages.error(request, _("No departments are involved in this complaint. Please add a department first."))
            return redirect("complaints:complaint_detail", pk=complaint.pk)

    if request.method == "POST":
        action = request.POST.get("action", "send")
        selected_dept_ids = request.POST.getlist("selected_departments")
        request_message = request.POST.get("request_message", "").strip()

        if not selected_dept_ids:
            messages.error(request, _("Please select at least one department."))
            return render(
                request,
                "complaints/send_to_department_form.html",
                {
                    "complaint": complaint,
                    "department_groups": department_groups,
                    "ungrouped_staff": ungrouped_staff,
                },
            )

        if action == "preview":
            preview_depts = []
            for dept_id in selected_dept_ids:
                dept_info = department_groups.get(dept_id)
                if dept_info:
                    contact_person_id = request.POST.get(f"contact_person_{dept_id}", "")
                    if contact_person_id:
                        from apps.organizations.models import Department as DeptModel
                        dept_obj = DeptModel.objects.filter(pk=dept_id).first()
                        if dept_obj:
                            cinfo = dept_obj.is_valid_contact_person(contact_person_id)
                            if cinfo:
                                dept_info["contact_person_id"] = contact_person_id
                                dept_info["contact_person_name"] = cinfo["name"]
                                dept_info["contact_person_role"] = cinfo["role_label"]
                                dept_info["contact_person_email"] = cinfo["email"]
                                dept_info["contact_person_staff"] = cinfo["staff"]
                    preview_depts.append(dept_info)

            contact_person_map = {
                d["department_id"]: d.get("contact_person_id", "")
                for d in preview_depts
                if d.get("contact_person_id")
            }

            return render(
                request,
                "complaints/send_to_department_preview.html",
                {
                    "complaint": complaint,
                    "preview_depts": preview_depts,
                    "selected_dept_ids": selected_dept_ids,
                    "request_message": request_message,
                    "contact_person_map": contact_person_map,
                },
            )

        from django.contrib.sites.shortcuts import get_current_site

        contact_person_map = {}
        for dept_id in selected_dept_ids:
            cp_id = request.POST.get(f"contact_person_{dept_id}", "")
            if cp_id:
                contact_person_map[dept_id] = cp_id

        site = get_current_site(request)
        results = ComplaintService.send_to_department(
            complaint,
            department_groups,
            selected_dept_ids,
            request_message,
            request.user,
            site.domain,
            request=request,
            contact_person_map=contact_person_map,
        )

        if not complaint.forwarded_to_dept_at:
            complaint.forwarded_to_dept_at = timezone.now()
            complaint.save(update_fields=["forwarded_to_dept_at"])

        if results["champion_count"] == 0 and results["manager_count"] == 0:
            if results["skipped_no_email"] > 0:
                messages.warning(
                    request,
                    _(
                        "No explanation requests were sent. {} department(s) have champions without email addresses."
                    ).format(results["skipped_no_email"]),
                )
            else:
                messages.warning(
                    request, _("No explanation requests were sent. Please check department champion configuration.")
                )
        elif results["champion_count"] == 0 and results["manager_count"] > 0:
            messages.warning(
                request,
                _(
                    "Only department manager notifications were sent ({}). Champion explanation requests could not be sent."
                ).format(results["manager_count"]),
            )
        else:
            messages.success(
                request,
                _("Explanation requests sent! Champions: {}, Department managers notified: {}.").format(
                    results["champion_count"], results["manager_count"]
                ),
            )
        return redirect("complaints:complaint_detail", pk=complaint.pk)

    return render(
        request,
        "complaints/send_to_department_form.html",
        {
            "complaint": complaint,
            "department_groups": department_groups,
            "ungrouped_staff": ungrouped_staff,
        },
    )
