from rest_framework.generics import (CreateAPIView, ListAPIView, RetrieveAPIView, UpdateAPIView, DestroyAPIView)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.filters import SearchFilter, OrderingFilter

from django.shortcuts import get_object_or_404
from django.db.models import Sum, OuterRef, Subquery, Value, DurationField, F, CharField
from django.db.models.functions import Concat
from datetime import date, datetime

from apps.employee.serializers.employee_serializers import EmployeeCreateAPISerializer,\
EmployeeListAPISerializer, EmployeeDetailAPISerializer, CurrentActivitySerializer, EmployeeUpdateAPISerializer, \
EmployeeAssignProjectSerializer, EmployeeDeleteAPISerializer

from apps.user.models import Role,User
from apps.project.models import Project
from apps.employee.models import Activity, TimeSheet



class EmployeeCreateAPIView(CreateAPIView):
    serializer_class = EmployeeCreateAPISerializer

    def perform_create(self, serializer):
        default_role = Role.objects.get(name='employee')

        serializer.save(role=default_role)


class EmployeeAssignProjectAPIView(APIView):
     def post(self, request, pk):

        try:
            user = User.objects.get(id=pk)
        except User.DoesNotExist:
            return Response({'message': 'User does not exist'}, status=status.HTTP_404_NOT_FOUND)

        serializer = EmployeeAssignProjectSerializer(data=request.data)
        if serializer.is_valid():
            project_id = serializer.validated_data.get('project_id', [])
            projects = Project.objects.filter(id__in=project_id)
            user.projects.add(*projects)
            return Response({'message': 'Projects has been assigned successfully'}, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class EmployeeUnAssignProjectAPIView(APIView):
    def post(self, request, pk):
        user = get_object_or_404(User, pk=pk)

        serializer = EmployeeAssignProjectSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        project_id = serializer.validated_data.get('project_id', [])
        projects = Project.objects.filter(id__in=project_id)

        user.projects.remove(*projects)

        return Response({'message': 'Projects has been unassigned successfully'}, status=status.HTTP_201_CREATED)


class EmployeeListAPIView(ListAPIView):
    serializer_class = EmployeeListAPISerializer
    filter_backends = [SearchFilter, OrderingFilter]
    search_fields = ['full_name', 'phone_no', 'email']
    ordering_fields = ['id', 'full_name', 'phone_no', 'email', 'pay_per_hour', 'total_working_duration', ]

    def get_queryset(self):
        project_id = self.request.query_params.get('project_id', None)
        include_all_employees = self.request.query_params.get('include_all_employees', False)
        is_active = self.request.query_params.get('is_active', None)
        employee_without_project_id = self.request.query_params.get('employee_without_project_id')
        with_trashed = self.request.query_params.get('with_trashed')

        queryset = User.objects.all().filter_employee().annotate_full_name()

        if with_trashed == 'true':
            queryset = User.objects.with_trashed().annotate_full_name().filter_employee()

        if project_id:

            if include_all_employees == 'true':
                activity_qs = Activity.objects.filter(user_id=OuterRef('pk'), project_id=OuterRef('activity__project_id')).values('user_id').annotate(total_working_duration=Sum('total_duration')).values('user_id', 'total_working_duration')
                queryset = queryset.filter(activity__project_id=project_id).distinct().annotate(total_working_duration=Subquery(activity_qs.values('total_working_duration')))
            else:
                activity_qs = Activity.objects.filter(user_id=OuterRef('pk'), project_id=OuterRef('projects__id')).values('user_id').annotate(total_working_duration=Sum('total_duration')).values('user_id', 'total_working_duration')
                queryset = queryset.filter(projects__id=project_id).annotate(total_working_duration=Subquery(activity_qs.values('total_working_duration')))
        else:
            activity_qs = Activity.objects.filter(user_id=OuterRef('pk')).values('user_id').annotate(total_working_duration=Sum('total_duration')).values('user_id', 'total_working_duration')
            queryset = queryset.annotate(total_working_duration=Subquery(activity_qs.values('total_working_duration')))

        if employee_without_project_id:
            queryset = queryset.exclude(projects__id=employee_without_project_id)

        if is_active is not None:
            queryset = queryset.filter(is_active=is_active.lower() == 'true')

        return queryset


class EmployeeDetailAPIView(RetrieveAPIView):
    serializer_class = EmployeeDetailAPISerializer
    queryset = User.objects.with_trashed().filter(role__name='employee').prefetch_related('projects').select_related('role')


class EmployeeEditAPIView(UpdateAPIView):
    http_method_names = ['patch']
    serializer_class = EmployeeUpdateAPISerializer
    queryset = User.objects.filter(role__name='employee')


class EmployeeDeleteAPIView(DestroyAPIView):
    serializer_class = EmployeeDeleteAPISerializer

    def delete(self, request, pk, *args, **kwargs):
        employee = get_object_or_404(User, pk=pk, role__name='employee')

        User.objects.filter(id=pk).update(deleted_by=self.request.user, deleted_at=datetime.now())

        serializer = self.serializer_class(employee)

        return Response(serializer.data)


class CurrentActivityAPIView(APIView):
    def get(self, request, format=None):

        current_activity_queryset = Activity.objects.filter(user=self.request.user, start_date_time__date=date.today(), status='started').select_related('user','project','activity_type').last()
        current_activity = CurrentActivitySerializer(current_activity_queryset).data if current_activity_queryset else None
        try:
            timesheet_entry = TimeSheet.objects.filter(user=request.user, clock_in_date_time__date=date.today()).last()
            clock_in_time = timesheet_entry.clock_in_date_time if timesheet_entry else None
            clock_out_time = timesheet_entry.clock_out_date_time if timesheet_entry else None
        except TimeSheet.DoesNotExist:
            clock_in_time = None
            clock_out_time = None

        return Response({
            'current_activity': current_activity,
            'clock_in_time': clock_in_time,
            'clock_out_time': clock_out_time
        })