from __future__ import annotations

from django.db.models import Q
from rest_framework import serializers, status
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.views import APIView

from apps.access.drf import TenantPermission
from apps.organizations.models import OrganizationMembership
from apps.personnel import services
from apps.personnel.models import Contract
from interfaces.api_v1.serializers import UserBriefSerializer

ORG = {m: "organization" for m in ("GET", "POST", "PATCH", "PUT", "DELETE")}


def _profile_data(membership) -> dict:
    profile = getattr(membership, "personnel_profile", None)
    return {
        "membership_id": membership.pk,
        "user": UserBriefSerializer(membership.user).data,
        "personnel_code": membership.personnel_code,
        "status": membership.status,
        "job_title": profile.job_title if profile else "",
        "department": profile.department if profile else "",
        "employment_type": profile.employment_type if profile else "full_time",
        "hire_date": profile.hire_date if profile else None,
        "end_date": profile.end_date if profile else None,
        "phone": profile.phone if profile else "",
        "emergency_contact": profile.emergency_contact if profile else "",
        "notes": profile.notes if profile else "",
    }


class ProfileInput(serializers.Serializer):
    job_title = serializers.CharField(max_length=120, required=False, allow_blank=True)
    department = serializers.CharField(max_length=120, required=False, allow_blank=True)
    employment_type = serializers.CharField(required=False)
    hire_date = serializers.DateField(required=False, allow_null=True)
    end_date = serializers.DateField(required=False, allow_null=True)
    phone = serializers.CharField(max_length=30, required=False, allow_blank=True)
    emergency_contact = serializers.CharField(max_length=200, required=False, allow_blank=True)
    notes = serializers.CharField(required=False, allow_blank=True)


class ContractSerializer(serializers.ModelSerializer):
    class Meta:
        model = Contract
        fields = ["id", "membership", "title", "start_date", "end_date", "pay_type", "pay_amount", "status", "notes"]
        read_only_fields = ["id", "membership"]


class Pagination(PageNumberPagination):
    page_size = 50
    page_size_query_param = "page_size"
    max_page_size = 100


class PersonnelListView(APIView):
    permission_classes = [TenantPermission]
    module_code = "personnel"
    permission_map = {"GET": "personnel.view"}

    def get(self, request):
        qs = services.visible_memberships(request.tenant).order_by("user__name", "id")
        params = request.query_params
        wanted = params.get("status")
        if wanted == "all":
            pass
        elif wanted:
            qs = qs.filter(status=wanted)
        else:  # people removed from the personnel list stay hidden unless asked for
            qs = qs.exclude(status=OrganizationMembership.Status.LEFT)
        search = (params.get("search") or "").strip()
        if search:
            qs = qs.filter(
                Q(user__name__icontains=search) | Q(personnel_code__icontains=search)
                | Q(personnel_profile__job_title__icontains=search) | Q(personnel_profile__department__icontains=search)
            )
        paginator = Pagination()
        page = paginator.paginate_queryset(qs, request)
        return paginator.get_paginated_response([_profile_data(m) for m in page])


class PersonnelDetailView(APIView):
    permission_classes = [TenantPermission]
    module_code = "personnel"
    permission_map = {"GET": "personnel.view", "PATCH": "personnel.update", "DELETE": "members.delete"}
    scope_map = {"PATCH": "organization", "DELETE": "organization"}

    def delete(self, request, pk):
        """Remove the person from the personnel list. The account itself is kept."""
        services.remove_from_personnel(request.tenant, pk, request=request)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def get(self, request, pk):
        return Response(_profile_data(services.get_membership(request.tenant, pk)))

    def patch(self, request, pk):
        data = ProfileInput(data=request.data, partial=True)
        data.is_valid(raise_exception=True)
        services.update_profile(request.tenant, pk, data=data.validated_data, request=request)
        return Response(_profile_data(services.get_membership(request.tenant, pk)))


class ContractListCreateView(APIView):
    permission_classes = [TenantPermission]
    module_code = "personnel"
    permission_map = {"GET": "personnel.contracts_view", "POST": "personnel.contracts_manage"}
    scope_map = ORG

    def get(self, request, pk):
        return Response(ContractSerializer(services.list_contracts(request.tenant, pk), many=True).data)

    def post(self, request, pk):
        data = ContractSerializer(data=request.data)
        data.is_valid(raise_exception=True)
        contract = services.create_contract(request.tenant, pk, data=dict(data.validated_data), request=request)
        return Response(ContractSerializer(contract).data, status=status.HTTP_201_CREATED)


class ContractDetailView(APIView):
    permission_classes = [TenantPermission]
    module_code = "personnel"
    permission_map = {"PATCH": "personnel.contracts_manage", "DELETE": "personnel.contracts_manage"}
    scope_map = ORG

    def patch(self, request, pk):
        contract = services.get_contract(request.tenant, pk)
        data = ContractSerializer(data=request.data, partial=True)
        data.is_valid(raise_exception=True)
        contract = services.update_contract(request.tenant, contract, data=dict(data.validated_data), request=request)
        return Response(ContractSerializer(contract).data)

    def delete(self, request, pk):
        services.delete_contract(request.tenant, services.get_contract(request.tenant, pk), request=request)
        return Response(status=status.HTTP_204_NO_CONTENT)
