import uuid
import os
from pathlib import Path

from django.http import Http404
from django.core.files.storage import FileSystemStorage
from django.conf import settings

from rest_framework import permissions
from rest_framework.decorators import action
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from rest_framework.parsers import FileUploadParser

from ichec_django_core.models import Member, FormFieldValue
from ichec_django_core.views import (
    ObjectFileDownloadView,
    SearchableModelViewSet,
)

from marinerg_test_access.models import AccessApplication
from marinerg_test_access.serializers import (
    AccessApplicationCreateSerializer,
    AccessApplicationDetailSerializer,
)


def is_consortium_admin(user):
    for group in user.groups.all():
        if group.name == "consortium_admins":
            return True
    return False


def is_on_access_board(application, user):
    if user.id == application.call.board_chair.id:
        return True

    for member in application.call.board_members.all():
        if member.id == user.id:
            return True
    return False


def is_call_coordinator(application, user):
    return application.call.coordinator.id == user.id


class ApplicationPermissions(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):

        if request.method in ["OPTIONS", "HEAD", "POST"]:
            return True

        if obj.applicant.id == request.user.id:
            return True
        if is_consortium_admin(request.user):
            return True

        if request.method in ["GET", "PUT", "PATCH"]:
            if is_on_access_board(obj, request.user):
                return True
            if is_call_coordinator(obj, request.user):
                return True
        return False


class AccessApplicationViewSet(SearchableModelViewSet):
    queryset = AccessApplication.objects.all()
    serializer_class = AccessApplicationDetailSerializer
    permission_classes = [
        permissions.IsAuthenticated,
        ApplicationPermissions,
    ]

    ordering: tuple[str, ...] = ("created_at",)
    search_fields = ["applicant__usename"]

    serializers = {
        "retrieve": AccessApplicationDetailSerializer,
        "list": AccessApplicationDetailSerializer,
        "create": AccessApplicationCreateSerializer,
        "update": AccessApplicationDetailSerializer,
        "partial_update": AccessApplicationDetailSerializer,
    }

    filterset_fields = (
        "applicant__id",
        "call__id",
        "facilities__id",
        "chosen_facility__id",
        "status",
    )

    @action(detail=True, url_path="summary", url_name="summary")
    def summary(self, request, pk=None):
        return self.download(request, "summary")

    def perform_create(self, serializer):
        serializer.save(applicant=Member.objects.get(id=self.request.user.id))


class ApplicationFieldDownloadView(ObjectFileDownloadView):

    model = AccessApplication
    permission_classes = [
        permissions.IsAuthenticated,
        ApplicationPermissions,
    ]

    def get_file(self):
        if not self.value.asset:
            raise Http404
        return self.value.asset

    def get_basename(self):
        ext = self.value.asset.name.split(".")[-1]
        return f"application_{self.value.field.key}.{ext}"

    def get(self, request, *args, **kwargs):
        self.authenticate(request)
        self.has_permission(request)

        self.object = self.get_object()
        self.value = FormFieldValue.objects.get(id=kwargs["value_id"])
        return super(ObjectFileDownloadView, self).get(request, *args, **kwargs)


class ApplicationFieldUploadView(GenericAPIView):

    model = AccessApplication
    queryset = AccessApplication.objects.all()
    parser_classes = [FileUploadParser]
    permission_classes = [
        permissions.IsAuthenticated,
        ApplicationPermissions,
    ]
    extensions = (".odt", ".doc", ".docx", ".pdf")

    def put(self, request, *args, **kwargs):
        value = FormFieldValue.objects.get(id=kwargs["value_id"])

        media_root = Path(settings.MEDIA_ROOT)
        instance = self.get_object()
        storage_dir = Path(f"{self.model._meta.model_name}/{instance.id}/field_values")
        os.makedirs(media_root / storage_dir, exist_ok=True)

        filename = request.data["file"].name

        _, ext = os.path.splitext(filename)
        if ext not in self.extensions:
            return Response(
                {"reason": "File extension not supported"},
                status=400,
            )

        file_path = f"{uuid.uuid4()}{ext}"
        written_path = FileSystemStorage(location=media_root / storage_dir).save(
            file_path, request.data["file"]
        )

        value.asset.original_file_name = filename
        value.asset.name = str(storage_dir / written_path)
        value.save()

        return Response(status=204)
