import structlog
from django.shortcuts import get_object_or_404
from rest_framework.decorators import api_view
from rest_framework.exceptions import PermissionDenied
from rest_framework.response import Response
from wagtail.models import Page

from vbv_lernwelt.course.models import (
    CircleDocument,
    CourseCompletion,
    CourseSession,
    CourseSessionUser,
)
from vbv_lernwelt.course.permissions import (
    course_sessions_for_user_qs,
    has_course_access,
    has_course_access_by_page_request,
    is_circle_expert,
    is_course_session_expert,
)
from vbv_lernwelt.course.serializers import (
    CourseCompletionSerializer,
    CourseSessionSerializer,
    DocumentUploadFinishInputSerializer,
    DocumentUploadStartInputSerializer,
)
from vbv_lernwelt.course.services import mark_course_completion
from vbv_lernwelt.files.models import UploadFile
from vbv_lernwelt.files.services import FileDirectUploadService
from vbv_lernwelt.learnpath.utils import get_wagtail_type

logger = structlog.get_logger(__name__)


@api_view(["GET"])
def course_page_api_view(request, slug_or_id):
    try:
        if slug_or_id.isdigit():
            page = Page.objects.get(id=slug_or_id)
        else:
            page = Page.objects.get(slug=slug_or_id, locale__language_code="de-CH")
        if not has_course_access_by_page_request(request, page):
            raise PermissionDenied()

        data = page.specific.get_serializer_class()(page.specific).data

        return Response(data)
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.exception(e)
        return Response({"error": str(e)}, status=404)


def _request_course_completion(course_session_id, user_id):
    try:
        response_data = CourseCompletionSerializer(
            CourseCompletion.objects.filter(
                user_id=user_id, course_session_id=course_session_id
            ),
            many=True,
        ).data

        return Response(status=200, data=response_data)
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.error(e)
        return Response({"error": str(e)}, status=404)


@api_view(["GET"])
def request_course_completion(request, course_session_id):
    course_id = get_object_or_404(CourseSession, id=course_session_id).course_id
    if has_course_access(request.user, course_id):
        return _request_course_completion(course_session_id, request.user.id)
    raise PermissionDenied()


@api_view(["GET"])
def request_course_completion_for_user(request, course_session_id, user_id):
    if request.user.id == user_id or is_course_session_expert(
        request.user, course_session_id
    ):
        return _request_course_completion(course_session_id, user_id)
    raise PermissionDenied()


@api_view(["POST"])
def mark_course_completion_view(request):
    try:
        page_key = request.data.get("page_key")
        completion_status = request.data.get("completion_status", "success")
        course_session_id = request.data.get("course_session_id")
        page = Page.objects.get(translation_key=page_key, locale__language_code="de-CH")

        if not has_course_access_by_page_request(request, page):
            raise PermissionDenied()

        page_type = get_wagtail_type(page.specific)
        course = page.specific.get_course()

        mark_course_completion(
            page_key,
            request.user,
            course_session=CourseSession.objects.get(id=course_session_id),
            completion_status=completion_status,
        )

        response_data = CourseCompletionSerializer(
            CourseCompletion.objects.filter(
                user=request.user, course_session_id=course_session_id
            ),
            many=True,
        ).data

        logger.debug(
            "mark_course_completion successful",
            label="completion_api",
            page_key=page_key,
            page_type=page_type,
            page_slug=page.slug,
            page_title=page.title,
            user_id=request.user.id,
            course_session_id=course_session_id,
            completion_status=completion_status,
        )

        return Response(status=200, data=response_data)
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.error(e, exc_info=True)
        return Response({"error": str(e)}, status=404)


@api_view(["GET"])
def get_course_sessions(request):
    try:
        course_sessions = course_sessions_for_user_qs(request.user)
        return Response(
            status=200, data=CourseSessionSerializer(course_sessions, many=True).data
        )
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.error(e, exc_info=True)
        return Response({"error": str(e)}, status=404)


@api_view(["GET"])
def get_course_session_users(request, course_session_id):
    try:
        qs = CourseSessionUser.objects.filter(course_session_id=course_session_id)

        user_data = [csu.to_dict() for csu in qs]
        return Response(status=200, data=user_data)
    except PermissionDenied as e:
        raise e
    except Exception as e:
        logger.error(e)
        return Response({"error": str(e)}, status=404)


@api_view(["POST"])
def document_upload_start(request):
    serializer = DocumentUploadStartInputSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)

    if not is_circle_expert(
        request.user,
        serializer.validated_data["course_session"],
        serializer.validated_data["learning_sequence"],
    ):
        raise PermissionDenied()

    service = FileDirectUploadService(request.user)
    file, presigned_data = service.start(
        serializer.validated_data["file_name"], serializer.validated_data["file_type"]
    )

    document = CircleDocument(
        file=file,
        name=serializer.validated_data["name"],
        course_session_id=serializer.validated_data["course_session"],
        learning_sequence_id=serializer.validated_data["learning_sequence"],
    )
    document.save()
    presigned_data["id"] = document.id
    presigned_data["file_id"] = file.id

    return Response(data=presigned_data)


@api_view(["POST"])
def document_upload_finish(request):
    serializer = DocumentUploadFinishInputSerializer(data=request.data)
    serializer.is_valid(raise_exception=True)

    file_id = serializer.validated_data["file_id"]
    file = get_object_or_404(UploadFile, id=file_id)

    if file.uploaded_by != request.user:
        raise PermissionDenied()

    service = FileDirectUploadService(request.user)
    service.finish(file=file)

    return Response({"url": file.url})


@api_view(["POST"])
def document_direct_upload(request, file_id):
    file = get_object_or_404(UploadFile, id=file_id)

    file_obj = request.FILES["file"]

    service = FileDirectUploadService(request.user)
    file = service.upload_local(file=file, file_obj=file_obj)

    return Response({"url": file.url})


@api_view(["DELETE"])
def document_delete(request, document_id):
    document = get_object_or_404(CircleDocument, id=document_id)
    if not is_circle_expert(
        request.user, document.course_session.id, document.learning_sequence.id
    ):
        raise PermissionDenied()

    document.delete()

    return Response(status=200)
