"""
On-Call Admin Schedule UI Views

Views for managing on-call admin schedules and assignments.
Only PX Admins can access these views.
"""

import logging

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db import transaction
from django.db.models import Q
from django.shortcuts import get_object_or_404, redirect, render
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from django.views.decorators.http import require_http_methods

from apps.accounts.models import User
from apps.core.services import AuditService
from apps.organizations.models import Hospital

from .models import OnCallAdminSchedule, OnCallAdmin

logger = logging.getLogger(__name__)


def check_px_admin(request):
    """Check if user is PX Admin, return redirect if not."""
    if not request.user.is_px_admin():
        messages.error(request, _("You do not have permission to access this page."))
        return redirect("dashboard")
    return None


@login_required
def oncall_schedule_list(request):
    """
    List all on-call schedules (system-wide and hospital-specific).
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    schedules = OnCallAdminSchedule.objects.select_related("hospital").all()

    context = {
        "schedules": schedules,
        "title": _("On-Call Admin Schedules"),
    }

    return render(request, "complaints/oncall/schedule_list.html", context)


@login_required
def oncall_schedule_create(request):
    """
    Create a new on-call schedule.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    hospitals = Hospital.objects.filter(status="active")

    if request.method == "POST":
        try:
            # Parse working days from checkboxes
            working_days = []
            for day in range(7):
                if request.POST.get(f"working_day_{day}"):
                    working_days.append(day)

            if not working_days:
                working_days = [0, 1, 2, 3, 4]  # Default to Mon-Fri

            # Get form data
            hospital_id = request.POST.get("hospital")
            hospital = Hospital.objects.get(id=hospital_id) if hospital_id else None

            work_start_time = request.POST.get("work_start_time", "08:00")
            work_end_time = request.POST.get("work_end_time", "17:00")
            timezone_str = request.POST.get("timezone", "Asia/Riyadh")
            is_active = request.POST.get("is_active") == "on"

            # Create schedule
            schedule = OnCallAdminSchedule.objects.create(
                hospital=hospital,
                working_days=working_days,
                work_start_time=work_start_time,
                work_end_time=work_end_time,
                timezone=timezone_str,
                is_active=is_active,
            )

            # Log audit
            AuditService.log_event(
                event_type="oncall_schedule_created",
                description=f"On-call schedule created: {schedule}",
                user=request.user,
                content_object=schedule,
                metadata={
                    "hospital": str(hospital) if hospital else "system-wide",
                    "working_days": working_days,
                    "work_hours": f"{work_start_time}-{work_end_time}",
                },
            )

            messages.success(request, _("On-call schedule created successfully."))
            return redirect("complaints:oncall_schedule_detail", pk=schedule.id)

        except Exception as e:
            logger.error(f"Error creating on-call schedule: {str(e)}")
            messages.error(request, _("Error creating on-call schedule. Please try again."))

    context = {
        "hospitals": hospitals,
        "timezones": [
            "Asia/Riyadh",
            "Asia/Dubai",
            "Asia/Kuwait",
            "Asia/Qatar",
            "Asia/Bahrain",
            "Asia/Muscat",
            "Asia/Amman",
            "Asia/Beirut",
            "Asia/Cairo",
            "Asia/Jerusalem",
            "Asia/Baghdad",
        ],
        "title": _("Create On-Call Schedule"),
    }

    return render(request, "complaints/oncall/schedule_form.html", context)


@login_required
def oncall_schedule_detail(request, pk):
    """
    View on-call schedule details with list of assigned admins.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    schedule = get_object_or_404(OnCallAdminSchedule.objects.select_related("hospital"), pk=pk)

    on_call_admins = schedule.on_call_admins.select_related("admin_user").all()

    # Check if currently working hours
    is_working_hours = schedule.is_working_time()

    context = {
        "schedule": schedule,
        "on_call_admins": on_call_admins,
        "is_working_hours": is_working_hours,
        "title": _("On-Call Schedule Details"),
    }

    return render(request, "complaints/oncall/schedule_detail.html", context)


@login_required
def oncall_schedule_edit(request, pk):
    """
    Edit an on-call schedule.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    schedule = get_object_or_404(OnCallAdminSchedule, pk=pk)
    hospitals = Hospital.objects.filter(status="active")

    if request.method == "POST":
        try:
            # Parse working days from checkboxes
            working_days = []
            for day in range(7):
                if request.POST.get(f"working_day_{day}"):
                    working_days.append(day)

            if not working_days:
                working_days = [0, 1, 2, 3, 4]  # Default to Mon-Fri

            # Get form data
            hospital_id = request.POST.get("hospital")
            schedule.hospital = Hospital.objects.get(id=hospital_id) if hospital_id else None

            schedule.working_days = working_days
            schedule.work_start_time = request.POST.get("work_start_time", "08:00")
            schedule.work_end_time = request.POST.get("work_end_time", "17:00")
            schedule.timezone = request.POST.get("timezone", "Asia/Riyadh")
            schedule.is_active = request.POST.get("is_active") == "on"

            schedule.save()

            # Log audit
            AuditService.log_event(
                event_type="oncall_schedule_updated",
                description=f"On-call schedule updated: {schedule}",
                user=request.user,
                content_object=schedule,
                metadata={
                    "hospital": str(schedule.hospital) if schedule.hospital else "system-wide",
                    "working_days": working_days,
                    "is_active": schedule.is_active,
                },
            )

            messages.success(request, _("On-call schedule updated successfully."))
            return redirect("complaints:oncall_schedule_detail", pk=schedule.id)

        except Exception as e:
            logger.error(f"Error updating on-call schedule: {str(e)}")
            messages.error(request, _("Error updating on-call schedule. Please try again."))

    context = {
        "schedule": schedule,
        "hospitals": hospitals,
        "timezones": [
            "Asia/Riyadh",
            "Asia/Dubai",
            "Asia/Kuwait",
            "Asia/Qatar",
            "Asia/Bahrain",
            "Asia/Muscat",
            "Asia/Amman",
            "Asia/Beirut",
            "Asia/Cairo",
            "Asia/Jerusalem",
            "Asia/Baghdad",
        ],
        "title": _("Edit On-Call Schedule"),
    }

    return render(request, "complaints/oncall/schedule_form.html", context)


@login_required
@require_http_methods(["POST"])
def oncall_schedule_delete(request, pk):
    """
    Delete an on-call schedule.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    schedule = get_object_or_404(OnCallAdminSchedule, pk=pk)

    try:
        # Log before deletion
        AuditService.log_event(
            event_type="oncall_schedule_deleted",
            description=f"On-call schedule deleted: {schedule}",
            user=request.user,
            metadata={
                "hospital": str(schedule.hospital) if schedule.hospital else "system-wide",
                "schedule_id": str(pk),
            },
        )

        schedule.delete()
        messages.success(request, _("On-call schedule deleted successfully."))

    except Exception as e:
        logger.error(f"Error deleting on-call schedule: {str(e)}")
        messages.error(request, _("Error deleting on-call schedule."))

    return redirect("complaints:oncall_schedule_list")


@login_required
def oncall_admin_add(request, schedule_pk):
    """
    Add an admin to the on-call schedule.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    schedule = get_object_or_404(OnCallAdminSchedule, pk=schedule_pk)

    # Get all PX Admins not already on this schedule
    existing_admin_ids = schedule.on_call_admins.values_list("admin_user_id", flat=True)
    available_admins = (
        User.objects.filter(
            Q(groups__name="PX Admin") | Q(groups__name="PX Employee") | Q(groups__name="Hospital Admin"),
            is_active=True,
        )
        .exclude(id__in=existing_admin_ids)
        .distinct()
    )

    if request.method == "POST":
        try:
            admin_user_id = request.POST.get("admin_user")
            if not admin_user_id:
                messages.error(request, _("Please select an admin user."))
                return redirect("complaints:oncall_admin_add", schedule_pk=schedule_pk)

            admin_user = User.objects.get(id=admin_user_id)

            # Parse dates
            start_date = request.POST.get("start_date") or None
            end_date = request.POST.get("end_date") or None

            # Create on-call admin assignment
            on_call_admin = OnCallAdmin.objects.create(
                schedule=schedule,
                admin_user=admin_user,
                start_date=start_date,
                end_date=end_date,
                notification_priority=int(request.POST.get("notification_priority", 1)),
                is_active=request.POST.get("is_active") == "on",
                notify_email=request.POST.get("notify_email") == "on",
                notify_sms=request.POST.get("notify_sms") == "on",
                sms_phone=request.POST.get("sms_phone", ""),
            )

            # Log audit
            AuditService.log_event(
                event_type="oncall_admin_added",
                description=f"Admin {admin_user.get_full_name()} added to on-call schedule",
                user=request.user,
                content_object=on_call_admin,
                metadata={
                    "schedule": str(schedule),
                    "admin_user": str(admin_user),
                    "start_date": start_date,
                    "end_date": end_date,
                },
            )

            messages.success(request, _("On-call admin added successfully."))
            return redirect("complaints:oncall_schedule_detail", pk=schedule_pk)

        except Exception as e:
            logger.error(f"Error adding on-call admin: {str(e)}")
            messages.error(request, _("Error adding on-call admin. Please try again."))

    context = {
        "schedule": schedule,
        "available_admins": available_admins,
        "available_px_admins": available_admins.filter(groups__name="PX Admin"),
        "available_px_employee": available_admins.filter(groups__name="PX Employee"),
        "available_hospital_admins": available_admins.filter(groups__name="Hospital Admin"),
        "title": _("Add On-Call Admin"),
    }

    return render(request, "complaints/oncall/admin_form.html", context)


@login_required
def oncall_admin_edit(request, pk):
    """
    Edit an on-call admin assignment.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    on_call_admin = get_object_or_404(OnCallAdmin.objects.select_related("schedule", "admin_user"), pk=pk)

    if request.method == "POST":
        try:
            # Parse dates
            start_date = request.POST.get("start_date") or None
            end_date = request.POST.get("end_date") or None

            # Update fields
            on_call_admin.start_date = start_date
            on_call_admin.end_date = end_date
            on_call_admin.notification_priority = int(request.POST.get("notification_priority", 1))
            on_call_admin.is_active = request.POST.get("is_active") == "on"
            on_call_admin.notify_email = request.POST.get("notify_email") == "on"
            on_call_admin.notify_sms = request.POST.get("notify_sms") == "on"
            on_call_admin.sms_phone = request.POST.get("sms_phone", "")

            on_call_admin.save()

            # Log audit
            AuditService.log_event(
                event_type="oncall_admin_updated",
                description=f"On-call admin updated: {on_call_admin}",
                user=request.user,
                content_object=on_call_admin,
                metadata={
                    "schedule": str(on_call_admin.schedule),
                    "admin_user": str(on_call_admin.admin_user),
                    "is_active": on_call_admin.is_active,
                },
            )

            messages.success(request, _("On-call admin updated successfully."))
            return redirect("complaints:oncall_schedule_detail", pk=on_call_admin.schedule.id)

        except Exception as e:
            logger.error(f"Error updating on-call admin: {str(e)}")
            messages.error(request, _("Error updating on-call admin. Please try again."))

    context = {
        "on_call_admin": on_call_admin,
        "schedule": on_call_admin.schedule,
        "title": _("Edit On-Call Admin"),
    }

    return render(request, "complaints/oncall/admin_form.html", context)


@login_required
@require_http_methods(["POST"])
def oncall_admin_delete(request, pk):
    """
    Remove an admin from the on-call schedule.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    on_call_admin = get_object_or_404(OnCallAdmin.objects.select_related("schedule", "admin_user"), pk=pk)
    schedule_pk = on_call_admin.schedule.id

    try:
        # Log before deletion
        AuditService.log_event(
            event_type="oncall_admin_removed",
            description=f"Admin removed from on-call schedule: {on_call_admin}",
            user=request.user,
            metadata={
                "schedule": str(on_call_admin.schedule),
                "admin_user": str(on_call_admin.admin_user),
                "oncall_admin_id": str(pk),
            },
        )

        on_call_admin.delete()
        messages.success(request, _("On-call admin removed successfully."))

    except Exception as e:
        logger.error(f"Error removing on-call admin: {str(e)}")
        messages.error(request, _("Error removing on-call admin."))

    return redirect("complaints:oncall_schedule_detail", pk=schedule_pk)


@login_required
def oncall_dashboard(request):
    """
    Dashboard view showing current on-call status and admins.
    """
    redirect_response = check_px_admin(request)
    if redirect_response:
        return redirect_response

    # Get all schedules
    schedules = OnCallAdminSchedule.objects.select_related("hospital").all()

    # Get currently active on-call admins
    now = timezone.now()
    today = now.date()

    active_on_call_admins = (
        OnCallAdmin.objects.filter(is_active=True, schedule__is_active=True)
        .select_related("admin_user", "schedule", "schedule__hospital")
        .filter(
            Q(start_date__isnull=True) | Q(start_date__lte=today), Q(end_date__isnull=True) | Q(end_date__gte=today)
        )
    )

    # Check each schedule's current status
    schedule_statuses = []
    for schedule in schedules:
        is_working = schedule.is_working_time()
        schedule_oncall = active_on_call_admins.filter(schedule=schedule)

        schedule_statuses.append(
            {
                "schedule": schedule,
                "is_working_hours": is_working,
                "on_call_count": schedule_oncall.count(),
                "on_call_admins": schedule_oncall,
            }
        )

    context = {
        "schedule_statuses": schedule_statuses,
        "total_schedules": schedules.count(),
        "total_active_oncall": active_on_call_admins.count(),
        "current_time": now,
        "title": _("On-Call Dashboard"),
    }

    return render(request, "complaints/oncall/dashboard.html", context)
