from collections.abc import Mapping

from django.contrib.auth.decorators import login_required
from django.core.handlers.wsgi import WSGIRequest
from django.http import Http404, HttpResponse, HttpResponseForbidden
from django.shortcuts import render
from django.views.decorators.http import require_GET

from vuln_demo.apps.vulnerabilities.levels.abc import LevelABC
from vuln_demo.apps.vulnerabilities.levels.level1 import Level1
from vuln_demo.apps.vulnerabilities.levels.level2 import Level2
from vuln_demo.apps.vulnerabilities.levels.level3 import Level3
from vuln_demo.apps.vulnerabilities.levels.level4 import Level4
from vuln_demo.apps.vulnerabilities.levels.level5 import Level5
from vuln_demo.apps.vulnerabilities.levels.level6 import Level6
from vuln_demo.apps.vulnerabilities.levels.level7 import Level7
from vuln_demo.apps.vulnerabilities.levels.level8 import Level8
from vuln_demo.apps.vulnerabilities.models import CompletedLevel
from vuln_demo.util.auth import cast_user

LEVELS: Mapping[int, type[LevelABC]] = {
    1: Level1,
    2: Level2,
    3: Level3,
    4: Level4,
    5: Level5,
    6: Level6,
    7: Level7,
    8: Level8,
}


@login_required
@require_GET
def vulnerabilities_index(request: WSGIRequest) -> HttpResponse:
    """Render the home/index page."""
    return render(request, "vulnerabilities/index.html")


@login_required
def level_view(request: WSGIRequest, level_num: int) -> HttpResponse:
    """Return the appropriate view for requested level."""
    level_cls = LEVELS.get(level_num)

    if not level_cls:
        raise Http404("Level does not exist")

    level_inst = level_cls()
    return level_inst.dispatch(request)


@login_required
@require_GET
def level_hint_view(request: WSGIRequest, level_num: int, hint_num: int) -> HttpResponse:
    """
    Obtain the hint text (HTML) for given level, and mark the use of hint.

    This is generally only called as an HTMX request, replacing the hint text
    shown in a modal.
    """
    # Direct to level hint func
    level_cls = LEVELS.get(level_num)

    if not level_cls:
        raise Http404("Level does not exist")

    # Get hint HTML for requested level
    return level_cls.get_hint(request, level_num, hint_num)


@login_required
@require_GET
def level_completed_view(request: WSGIRequest, level_num: int) -> HttpResponse:
    """Show a success page if the user actually completed given level."""
    level_cls = LEVELS.get(level_num)

    if not level_cls:
        raise Http404("Level does not exist")

    # Check if this user actually completed this level
    assert cast_user(request.user, cast=True)
    if not CompletedLevel.check_completed(request.user, level_num):
        return HttpResponseForbidden("Good try, but you gotta actually solve the level")

    # Set next level, if available
    next_level = level_num + 1 if LEVELS.get(level_num + 1) else None

    return render(request, "vulnerabilities/completed.html", {"current_level": level_num, "next_level": next_level})
