from rest_framework.generics import ListAPIView
from rest_framework.response import Response

from datetime import date, datetime

from django.db.models import Sum, Case, When, Q, BooleanField
from django.db.models.functions import TruncDate

from calendar import monthrange

from apps.employee.models import Activity

from core.utils.convert_json_to_excel import generate_excel_file

from core.utils.helper import format_amount_with_currency

from apps.employee.services.summary_services import get_activities_by_week
from apps.employee.serializers.summary_serializers import SummaryActivitySerializer, SummaryActivityDurationSerializer

from collections import defaultdict



class SummaryAPIView(ListAPIView):
    queryset = Activity.objects.all()

    def list(self, request, *args, **kwargs):
        start_date = request.query_params.get('start_date', date.today())
        end_date = request.query_params.get('end_date', date.today())

        project_id = request.query_params.get('project_id')
        client_id = request.query_params.get('client_id')
        activity_type_id = request.query_params.get('activity_type_id')
        user_id = request.query_params.get('user_id')
        with_trashed = self.request.query_params.get('with_trashed')

        activities = Activity.objects.filter(start_date_time__date__range=[start_date, end_date]) \
            .select_related('project', 'activity_type', 'user') \
            .annotate(
                is_resumable_activity = Case(
                    When(Q(activity_type__is_active=True) & Q(project__deleted_at__isnull=True) & Q(project__client__deleted_at__isnull=True), then=True),
                    default=False,
                    output_field=BooleanField(),
                )
            ).order_by('start_date_time')

        if with_trashed == 'true':
            activities = Activity.objects.with_trashed().filter(start_date_time__date__range=[start_date, end_date]) \
            .select_related('project', 'activity_type', 'user') \
            .annotate(
                is_resumable_activity = Case(
                    When(Q(activity_type__is_active=True) & Q(project__deleted_at__isnull=True) & Q(project__client__deleted_at__isnull=True), then=True),
                    default=False,
                    output_field=BooleanField(),
                )
            ).order_by('start_date_time')

        if self.request.user and self.request.user.role and self.request.user.role.name != 'admin':
            activities = activities.filter(user_id=user_id)

        if project_id:
            activities = activities.filter(project_id=project_id)

        if client_id:
            activities = activities.filter(project__client_id=client_id)

        if activity_type_id:
            activities = activities.filter(activity_type_id=activity_type_id)

        if user_id:
            activities = activities.filter(user_id=user_id)

        total_sum_data_queryset = activities.annotate(date=TruncDate('start_date_time')).values('date').annotate(total_duration_sum=Sum('total_duration')).order_by('date')

        serializer = SummaryActivitySerializer(activities, many=True)
        data = self.paginate_queryset(serializer.data)

        total_sum_data = SummaryActivityDurationSerializer(total_sum_data_queryset, many=True).data

        activities_by_week = get_activities_by_week(data, total_sum_data)

        return self.get_paginated_response(activities_by_week[::-1])


class SummaryExcelAPIView(ListAPIView):
    queryset = Activity.objects.all()

    def list(self, request, *args, **kwargs):
        start_date = request.query_params.get('start_date', date.today())
        end_date = request.query_params.get('end_date', date.today())

        project_id = request.query_params.get('project_id')
        client_id = request.query_params.get('client_id')
        activity_type_id = request.query_params.get('activity_type_id')
        user_id = request.query_params.get('user_id')
        with_trashed = self.request.query_params.get('with_trashed')

        # base queryset
        activities = Activity.objects.filter(start_date_time__date__range=[start_date, end_date ]) \
            .select_related('project', 'activity_type', 'user') \
            .annotate(
                is_resumable_activity = Case(
                    When(Q(activity_type__is_active=True) & Q(project__deleted_at__isnull=True) & Q(project__client__deleted_at__isnull=True), then=True),
                    default=False,
                    output_field=BooleanField(),
                )
            ).order_by("start_date_time__date", "user__id", "start_date_time")

        if with_trashed == 'true':
            activities = Activity.objects.with_trashed().filter(start_date_time__date__range=[start_date, end_date ]) \
            .select_related('project', 'activity_type', 'user') \
            .annotate(
                is_resumable_activity = Case(
                    When(Q(activity_type__is_active=True) & Q(project__deleted_at__isnull=True) & Q(project__client__deleted_at__isnull=True), then=True),
                    default=False,
                    output_field=BooleanField(),
                )
            ).order_by("start_date_time__date", "user__id", "start_date_time")

        if self.request.user and self.request.user.role and self.request.user.role.name != 'admin':
            activities = activities.filter(user_id=user_id)

        if project_id:
            activities = activities.filter(project_id=project_id)

        if client_id:
            activities = activities.filter(project__client_id=client_id)

        if activity_type_id:
            activities = activities.filter(activity_type_id=activity_type_id)

        if user_id:
            activities = activities.filter(user_id=user_id)

        data = []
        daily_totals = defaultdict(float)

        for activity in activities:
            if activity.total_duration and activity.pay_per_hour:
                total_hours = activity.total_duration.total_seconds() / 3600
                daily_totals[(activity.user_id, activity.start_date_time.date())] += (
                    total_hours * activity.pay_per_hour
                )

        prev_key = None
        for activity in activities:
            total_duration = str(activity.total_duration) if activity.total_duration else ""
            row_cost = ""
            numeric_cost = 0

            if activity.total_duration and activity.pay_per_hour:
                total_hours = activity.total_duration.total_seconds() / 3600
                numeric_cost = total_hours * activity.pay_per_hour
                row_cost = format_amount_with_currency(numeric_cost)


            row = {
                "Date": activity.start_date_time.strftime("%d-%m-%Y") if activity.start_date_time else "",
                "Employee Name": activity.user.get_full_name() if activity.user else "",
                "Project": activity.project.name if activity.project else "",
                "Activity Type": activity.activity_type.name if activity.activity_type else "",
                "Description": activity.description or "",
                "Start Time": activity.start_date_time.strftime("%H:%M") if activity.start_date_time else "",
                "End Time": activity.end_date_time.strftime("%H:%M") if activity.end_date_time else "",
                "Total": total_duration,
                "Cost": row_cost,
            }

            # determine if this is the last record of the group → add total_cost
            current_key = (activity.user_id, activity.start_date_time.date())
            if prev_key != current_key:
                # reset tracker for this group
                remaining = len([a for a in activities if (a.user_id, a.start_date_time.date()) == current_key])
            remaining -= 1
            if remaining == 0:
                row["Total Cost"] = format_amount_with_currency(daily_totals[current_key])

            data.append(row)
            prev_key = current_key

        # column order
        column_names = [
            "Date",
            "Employee Name",
            "Project",
            "Activity Type",
            "Description",
            "Start Time",
            "End Time",
            "Total Duration",
            "Cost",
            "Total Cost",
        ]

        # file name
        file_name = f"Summary Report - {start_date} to {end_date} #{datetime.now().strftime('%d-%m-%Y %H:%M')}"

        # generate Excel
        response = generate_excel_file(column_names, data, file_name)
        return response
