import json
import os
import tempfile
from pathlib import Path

from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
from django.views.decorators.http import require_http_methods


DEFAULT_SECONDS = 15 * 60
MAX_SECONDS = 8 * 60 * 60


def _is_authorised_admin(user):
    # Preserve the existing strict access control: active staff superusers only.
    return user.is_authenticated and user.is_active and user.is_staff and user.is_superuser


def _config_path():
    return Path(settings.BASE_DIR) / "session_timeout.json"


def _read_duration():
    try:
        with _config_path().open("r", encoding="utf-8") as file:
            data = json.load(file)

        if "seconds_total" in data:
            total = int(data["seconds_total"])
        elif any(key in data for key in ("hours", "minutes", "seconds")):
            total = (
                int(data.get("hours", 0)) * 3600
                + int(data.get("minutes", 0)) * 60
                + int(data.get("seconds", 0))
            )
        else:
            total = int(data.get("minutes", 15)) * 60

        if 1 <= total <= MAX_SECONDS:
            return total
    except (OSError, ValueError, TypeError, json.JSONDecodeError):
        pass
    return DEFAULT_SECONDS


def _duration_parts(total):
    hours, remainder = divmod(total, 3600)
    minutes, seconds = divmod(remainder, 60)
    return {"hours": hours, "minutes": minutes, "seconds": seconds}


def _save_duration(total):
    target = _config_path()
    temp_path = None
    hours, remainder = divmod(total, 3600)
    minutes, seconds = divmod(remainder, 60)

    try:
        with tempfile.NamedTemporaryFile(
            mode="w", encoding="utf-8", dir=str(target.parent),
            prefix=".session_timeout_", suffix=".tmp", delete=False
        ) as file:
            temp_path = file.name
            json.dump(
                {
                    "hours": hours,
                    "minutes": minutes,
                    "seconds": seconds,
                    "seconds_total": total,
                },
                file,
                indent=2,
            )
            file.write("\n")
            file.flush()
            os.fsync(file.fileno())

        os.replace(temp_path, target)
        return True
    except OSError:
        if temp_path:
            try:
                os.unlink(temp_path)
            except OSError:
                pass
        return False


def _render_settings(request, error_message=None):
    total = _read_duration()
    context = _duration_parts(total)
    context["total_seconds"] = total
    context["max_hours"] = 8
    if error_message:
        messages.error(request, error_message)
    return render(request, "accounts/session_settings.html", context)


@login_required
@require_http_methods(["GET", "POST"])
def session_settings(request):
    if not _is_authorised_admin(request.user):
        messages.error(
            request,
            "Access denied. Only authorised administrators can change session security settings.",
        )
        return redirect("dashboard")

    if request.method == "POST":
        try:
            hours = int(request.POST.get("hours", "0"))
            minutes = int(request.POST.get("minutes", "0"))
            seconds = int(request.POST.get("seconds", "0"))
        except (TypeError, ValueError):
            return _render_settings(request, "Enter whole numbers for hours, minutes, and seconds.")

        if hours < 0 or not 0 <= minutes <= 59 or not 0 <= seconds <= 59:
            return _render_settings(
                request,
                "Use non-negative hours and minutes/seconds between 0 and 59.",
            )

        total = hours * 3600 + minutes * 60 + seconds
        if not 1 <= total <= MAX_SECONDS:
            return _render_settings(
                request,
                "Timeout must be at least 1 second and no more than 8 hours.",
            )

        if _save_duration(total):
            messages.success(request, "Session inactivity timeout settings saved.")
            return redirect("session_settings")

        return _render_settings(request, "Could not save the setting. Check file permissions.")

    return _render_settings(request)
