from __future__ import annotations from rest_framework import serializers from apps.groups.models import ( FrequencyChoice, GroupMeeting, GroupMembership, NotificationPreference, PaceNotification, ReadingGroup, ) from apps.groups.services.pace import PaceStatus class NotificationPreferenceSerializer(serializers.ModelSerializer): class Meta: model = NotificationPreference fields = [ "pace_notifications_enabled", "reminder_enabled", "frequency", ] def validate_frequency(self, value: str) -> str: valid = {choice[0] for choice in FrequencyChoice.choices} if value not in valid: raise serializers.ValidationError( f"Frequency must be one of: {', '.join(valid)}" ) return value class GroupMeetingSerializer(serializers.ModelSerializer): group_name = serializers.CharField(source="group.name", read_only=True) class Meta: model = GroupMeeting fields = [ "id", "group", "group_name", "title", "scheduled_at", "target_section", "target_section_label", "created_at", ] read_only_fields = ["id", "created_at"] def validate_target_section(self, value: int) -> int: if value < 0: raise serializers.ValidationError("Target section must be non-negative.") return value class ReadingGroupSerializer(serializers.ModelSerializer): member_count = serializers.SerializerMethodField() meeting_count = serializers.SerializerMethodField() class Meta: model = ReadingGroup fields = [ "id", "name", "description", "book", "ebook", "created_by", "created_at", "member_count", "meeting_count", ] read_only_fields = ["id", "created_by", "created_at"] def get_member_count(self, obj: ReadingGroup) -> int: return obj.memberships.count() def get_meeting_count(self, obj: ReadingGroup) -> int: return obj.meetings.count() class GroupMembershipSerializer(serializers.ModelSerializer): user_email = serializers.CharField(source="user.email", read_only=True) group_name = serializers.CharField(source="group.name", read_only=True) class Meta: model = GroupMembership fields = ["id", "user", "user_email", "group", "group_name", "role", "joined_at"] read_only_fields = ["id", "joined_at"] class PaceNotificationSerializer(serializers.ModelSerializer): status_display = serializers.CharField(source="get_status_display", read_only=True) class Meta: model = PaceNotification fields = [ "id", "user", "meeting", "ebook", "status", "status_display", "current_section", "target_section", "ahead_behind_delta", "created_at", ] read_only_fields = ["id", "created_at"] class PaceStatusSerializer(serializers.Serializer): meeting_id = serializers.IntegerField() meeting_title = serializers.CharField() scheduled_at = serializers.CharField() target_section = serializers.IntegerField() target_section_label = serializers.CharField() current_section = serializers.IntegerField() ahead_behind_delta = serializers.IntegerField() status = serializers.CharField() days_until_meeting = serializers.IntegerField() sections_to_catch_up = serializers.IntegerField() ebook_id = serializers.IntegerField() ebook_title = serializers.CharField() class ReminderSerializer(serializers.Serializer): meeting_id = serializers.IntegerField() meeting_title = serializers.CharField() scheduled_at = serializers.CharField() target_section = serializers.IntegerField() target_section_label = serializers.CharField() group_name = serializers.CharField() hours_until = serializers.IntegerField() ebook_id = serializers.IntegerField() ebook_title = serializers.CharField()