from __future__ import annotations

from django.shortcuts import render
from django.contrib import messages
from django.core.paginator import Paginator
from django.db import transaction
from django.db.models import Count
from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse

from .forms import ScheduleForm, ScriptRootForm
from .models import Script, ScriptRoot, ScriptRun, Schedule
from .services import (
    create_run_record,
    finalize_run,
    run_script_as_runner,
    scan_root,
    set_script_root,
    compute_next_run_at,
)


def _get_request_user_hint(request: HttpRequest) -> str | None:
    # Nginx may set REMOTE_USER; if not, keep it blank.
    return request.META.get("REMOTE_USER")


def dashboard(request: HttpRequest) -> HttpResponse:
    root = ScriptRoot.objects.order_by("-updated_at").first()
    scripts_count = Script.objects.count()
    schedules_count = Schedule.objects.count()
    runs_count = ScriptRun.objects.count()
    recent = ScriptRun.objects.select_related("script").order_by("-started_at")[:10]
    return render(
        request,
        "scheduler/dashboard.html",
        {
            "root": root,
            "scripts_count": scripts_count,
            "schedules_count": schedules_count,
            "runs_count": runs_count,
            "recent": recent,
        },
    )


def settings_view(request: HttpRequest) -> HttpResponse:
    current = ScriptRoot.objects.order_by("-updated_at").first()
    if request.method == "POST":
        form = ScriptRootForm(request.POST)
        if form.is_valid():
            root = set_script_root(form.cleaned_data["path"])
            messages.success(request, f"Saved scripts folder: {root.path}")
            return redirect("scheduler:settings")
    else:
        form = ScriptRootForm(initial={"path": current.path if current else "/opt/scripts"})

    return render(request, "scheduler/settings.html", {"form": form, "current": current})


def scan_now(request: HttpRequest) -> HttpResponse:
    if request.method != "POST":
        return redirect("scheduler:settings")

    root = ScriptRoot.objects.order_by("-updated_at").first()
    if not root:
        messages.error(request, "No scripts folder configured.")
        return redirect("scheduler:settings")

    try:
        stats = scan_root(root)
        messages.success(
            request,
            f"Scan complete. Created {stats['created']}, updated {stats['updated']}, marked missing {stats['missing_marked']}.",
        )
    except Exception as e:
        messages.error(request, f"Scan failed: {e}")

    return redirect("scheduler:scripts")


def scripts_list(request: HttpRequest) -> HttpResponse:
    qs = Script.objects.select_related("root").annotate(schedule_count=Count("schedules")).order_by("name")
    return render(request, "scheduler/scripts_list.html", {"scripts": qs})


def script_detail(request: HttpRequest, script_id: int) -> HttpResponse:
    script = get_object_or_404(Script, id=script_id)
    schedules = script.schedules.order_by("-created_at")
    return render(request, "scheduler/script_detail.html", {"script": script, "schedules": schedules})


def run_now(request: HttpRequest, script_id: int) -> HttpResponse:
    if request.method != "POST":
        return redirect("scheduler:script_detail", script_id=script_id)

    script = get_object_or_404(Script, id=script_id)
    if not script.enabled or script.missing:
        messages.error(request, "Script is disabled or missing.")
        return redirect("scheduler:script_detail", script_id=script_id)

    run = create_run_record(script=script, schedule=None, requested_by=_get_request_user_hint(request))
    result = run_script_as_runner(script.abs_path, timeout_seconds=3600)
    finalize_run(run, result)

    if run.status == ScriptRun.STATUS_SUCCESS:
        messages.success(request, "Run completed successfully.")
    else:
        messages.error(request, f"Run finished with status: {run.status} (exit_code={run.exit_code})")

    return redirect("scheduler:run_detail", run_id=run.id)


def runs_list(request: HttpRequest) -> HttpResponse:
    qs = ScriptRun.objects.select_related("script").order_by("-started_at")
    paginator = Paginator(qs, 25)
    page = paginator.get_page(request.GET.get("page", "1"))
    return render(request, "scheduler/runs_list.html", {"page": page})


def run_detail(request: HttpRequest, run_id: int) -> HttpResponse:
    run = get_object_or_404(ScriptRun.objects.select_related("script", "schedule"), id=run_id)
    return render(request, "scheduler/run_detail.html", {"run": run})


def rerun(request: HttpRequest, run_id: int) -> HttpResponse:
    if request.method != "POST":
        return redirect("scheduler:run_detail", run_id=run_id)

    prev = get_object_or_404(ScriptRun.objects.select_related("script"), id=run_id)
    return run_now(request, script_id=prev.script_id)


def schedule_create(request: HttpRequest, script_id: int) -> HttpResponse:
    script = get_object_or_404(Script, id=script_id)
    if request.method == "POST":
        form = ScheduleForm(request.POST)
        if form.is_valid():
            sched = form.save(commit=False)
            sched.script = script
            sched.next_run_at = compute_next_run_at(sched)
            sched.save()
            messages.success(request, "Schedule created.")
            return redirect("scheduler:script_detail", script_id=script.id)
    else:
        form = ScheduleForm(initial={"enabled": True, "kind": Schedule.KIND_INTERVAL, "interval_minutes": 30})

    return render(request, "scheduler/schedule_form.html", {"form": form, "script": script, "mode": "create"})


def schedule_edit(request: HttpRequest, schedule_id: int) -> HttpResponse:
    sched = get_object_or_404(Schedule.objects.select_related("script"), id=schedule_id)
    if request.method == "POST":
        form = ScheduleForm(request.POST, instance=sched)
        if form.is_valid():
            sched = form.save(commit=False)
            # reset next_run when edited
            sched.next_run_at = compute_next_run_at(sched)
            sched.save()
            messages.success(request, "Schedule updated.")
            return redirect("scheduler:script_detail", script_id=sched.script_id)
    else:
        form = ScheduleForm(instance=sched)

    return render(request, "scheduler/schedule_form.html", {"form": form, "script": sched.script, "mode": "edit"})

@transaction.atomic
def clear_scripts(request):
    if request.method != "POST":
        return redirect("scheduler:scripts")

    count = Script.objects.count()
    Script.objects.all().delete()

    messages.success(request, f"Cleared {count} scripts, schedules, and run history.")
    return redirect("scheduler:scripts")

@transaction.atomic
def clear_script_history(request, script_id):
    if request.method != "POST":
        return redirect("scheduler:script_detail", script_id=script_id)

    script = get_object_or_404(Script, id=script_id)

    count = ScriptRun.objects.filter(script=script).count()
    ScriptRun.objects.filter(script=script).delete()

    messages.success(request, f"Cleared {count} history entries for '{script.name}'.")
    return redirect("scheduler:script_detail", script_id=script.id)
