import posixpath

from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_POST

from learn.models import Mock_Test, Question_Bank

from .question_video_service import (
    explanation_video_storage,
    mock_video_folder,
    parse_question_number,
)
from .question_video_jobs import (
    create_upload_job,
    ffmpeg_binary,
    read_job_status,
)


@login_required(login_url="/admin/login")
@require_POST
def bulk_upload_question_explanation_videos(request, mock_test_id):
    """Accept all numbered videos and process them sequentially in the background."""
    mock_test = get_object_or_404(Mock_Test, id=mock_test_id)
    videos = request.FILES.getlist("videos")

    if not ffmpeg_binary():
        return JsonResponse(
            {
                "error": "FFmpeg is not installed on the server. Install it or configure FFMPEG_BINARY."
            },
            status=503,
        )

    try:
        job = create_upload_job(mock_test, videos)
    except ValueError as exc:
        return JsonResponse({"error": str(exc)}, status=400)
    except Exception as exc:
        return JsonResponse(
            {"error": "Could not queue the video upload.", "details": str(exc)},
            status=500,
        )

    return JsonResponse(
        {
            "success": True,
            "message": (
                "{0} videos queued for background compression and upload."
                " {1} additional files shared a question tag and were not needed."
            ).format(job["total"], job.get("ignored_tag_duplicates", 0)),
            "job": job,
        },
        status=202,
    )


@login_required(login_url="/admin/login")
def question_video_upload_status(request, mock_test_id, job_id):
    status = read_job_status(job_id)
    if not status or int(status.get("mock_test_id", 0)) != mock_test_id:
        return JsonResponse({"error": "Upload job not found."}, status=404)
    return JsonResponse({"success": True, "job": status})


@login_required(login_url="/admin/login")
@require_POST
def sync_question_explanation_videos(request, mock_test_id):
    """Match manually uploaded Spaces videos to questions by question number."""
    mock_test = get_object_or_404(Mock_Test, id=mock_test_id)
    questions = list(
        Question_Bank.objects.filter(test_id=mock_test_id).order_by("section_id", "id")
    )
    if not questions:
        return JsonResponse({"error": "This mock test has no questions."}, status=400)

    storage = explanation_video_storage()
    folder = mock_video_folder(mock_test)
    try:
        _directories, filenames = storage.listdir(folder)
    except Exception as exc:
        return JsonResponse(
            {
                "error": "Could not read the DigitalOcean folder.",
                "details": [str(exc)],
                "folder": "media/{0}/".format(folder),
            },
            status=502,
        )

    first_number_by_tag = {}
    for number, question in enumerate(questions, start=1):
        tag = str(question.tag or "").strip()
        if tag and tag.lower() not in ("null", "none"):
            first_number_by_tag.setdefault(tag, number)

    matched_files = {}
    ignored_files = []
    for filename in filenames:
        try:
            question_number, _extension = parse_question_number(filename)
        except ValueError:
            ignored_files.append(filename)
            continue
        if 1 <= question_number <= len(questions):
            question = questions[question_number - 1]
            tag = str(question.tag or "").strip()
            if tag.lower() in ("null", "none"):
                tag = ""
            canonical_number = first_number_by_tag.get(tag, question_number) if tag else question_number
            existing = matched_files.get(canonical_number)
            candidate = {
                "source_number": question_number,
                "storage_name": posixpath.join(folder, filename),
                "tag": tag,
            }
            if existing is None or question_number == canonical_number:
                matched_files[canonical_number] = candidate
        else:
            ignored_files.append(filename)

    updated = 0
    for question_number, match in matched_files.items():
        storage_name = match["storage_name"]
        if match["tag"]:
            updated += Question_Bank.objects.filter(
                test_id=mock_test_id,
                tag=match["tag"],
            ).exclude(explanation_video=storage_name).update(
                explanation_video=storage_name
            )
        else:
            updated += Question_Bank.objects.filter(
                id=questions[question_number - 1].id,
                test_id=mock_test_id,
            ).exclude(explanation_video=storage_name).update(
                explanation_video=storage_name
            )

    uploaded = Question_Bank.objects.filter(
        test_id=mock_test_id,
        explanation_video__isnull=False,
    ).exclude(explanation_video="").count()
    refreshed_questions = list(
        Question_Bank.objects.filter(test_id=mock_test_id).order_by("section_id", "id")
    )

    return JsonResponse(
        {
            "success": True,
            "message": "Videos uploaded in mock: {0} of {1}.".format(
                uploaded,
                len(questions),
            ),
            "folder": "media/{0}/".format(folder),
            "total": len(questions),
            "uploaded": uploaded,
            "updated": updated,
            "missing": [
                number
                for number, question in enumerate(refreshed_questions, start=1)
                if not question.explanation_video
            ],
            "ignored_files": ignored_files,
        }
    )
