from rest_framework import serializers
from .models import *
from user_app.models import *
from user_app.serializers import AppUserSerializer, AssessmentAttempt
from django.db.models.functions import ExtractMonth
from django.db.models import Count
from django.db.models import Min
from datetime import timedelta
import ast



class ExerciseSerializer(serializers.ModelSerializer):
	class Meta:
		model = Exercise
		fields = ('id', 'name', 'description', 'image')


class SubExerciseSerializer(serializers.ModelSerializer):
	images = serializers.SerializerMethodField()
	videos = serializers.SerializerMethodField()
	focus_area = serializers.SerializerMethodField()
	class Meta:
		model = SubExercise
		fields = ('id', 'name', 'description', 'comments', 'note', 'focus_area', 'sets', 'reps','weight', 'youtube_link', 'videos','images')

	
	def get_images(self, obj):
		images_string = obj.images
		if images_string:
			images_array = images_string.strip("[]").replace("'", "").split(", ")
		else:
			images_array = []
		return images_array

	def get_videos(self, obj):
		videos_string = obj.videos
		if videos_string:
			videos_array = videos_string.strip("[]").replace("'", "").split(", ")
		else:
			videos_array = []
		return videos_array
	
	def get_focus_area(self, obj):
		focus_area_string = obj.focus_area
		if focus_area_string:
			focus_area = focus_area_string.strip("[]").replace("'", "").split(", ")
		else:
			focus_area = []
		return focus_area



class VideosSerializer(serializers.ModelSerializer):
	class Meta:
		model = Videos
		fields = '__all__'



# class TrainerSerializer(serializers.ModelSerializer):


# 	exercises = serializers.SerializerMethodField(source='get_exercises')
# 	videos = serializers.SerializerMethodField(source='get_videos')
# 	total_exercise = serializers.SerializerMethodField(source='get_total_exercise')
# 	speciality = serializers.SerializerMethodField(source='get_speciality')
# 	class Meta:
# 		model = Trainer
# 		fields = ['id','full_name', 'email', 'gender', 'age', 'image', 'speciality', 'description', 'total_experience', 'is_profile_completed','exercises','videos','total_exercise']

# 	def get_exercises(self,obj):
# 		exercise_obj=Exercise.objects.filter(trainer=obj)
# 		return ExerciseSerializer(exercise_obj,many=True).data
	
# 	def get_videos(self,obj):
# 		video_obj=Videos.objects.filter(trainer=obj)
# 		return VideosSerializer(video_obj,many=True).data

# 	def get_total_exercise(self, obj):
# 		return Exercise.objects.filter(trainer=obj).count()
	
# 	def get_speciality(self, obj):
# 		speciality_string = obj.speciality
# 		if speciality_string:
# 			speciality = speciality_string.strip("[]").replace("'", "").split(", ")
# 		else:
# 			speciality = []
# 		return speciality
	
class TrainerSerializer(serializers.ModelSerializer):
	exercises = serializers.SerializerMethodField(source='get_exercises')
	workout_plans = serializers.SerializerMethodField(source='get_workout_plans')
	videos = serializers.SerializerMethodField(source='get_videos')
	total_exercise = serializers.SerializerMethodField(source='get_total_exercise')
	speciality = serializers.SerializerMethodField(source='get_speciality')
	is_requested = serializers.SerializerMethodField(source='get_is_requested')

	
	class Meta:
		model = Trainer
		fields = ['id', 'full_name', 'email', 'gender', 'age', 'image', 'speciality', 'description','address','latitude','longitude',
				  'total_experience', 'is_profile_completed', 'exercises', 'workout_plans' ,'videos', 'total_exercise','is_requested']


	def get_exercises(self, obj):
		exercise_obj = Exercise.objects.filter(trainer=obj)[:10]
		return ExerciseSerializer(exercise_obj, many=True).data
	
	def get_workout_plans(self, obj):
		exercise_obj = WorkoutPlan.objects.filter(trainer=obj,work_access="public")[:10]
		return WorkoutPlanSerializer(exercise_obj, many=True).data

	def get_videos(self, obj):
		video_obj = Videos.objects.filter(trainer=obj)
		return VideosSerializer(video_obj, many=True).data

	def get_total_exercise(self, obj):
		return Exercise.objects.filter(trainer=obj).count()

	def get_speciality(self, obj):
		speciality_string = obj.speciality
		if speciality_string:
			speciality = speciality_string.strip("[]").replace("'", "").split(", ")
		else:
			speciality = []
		return speciality


	def get_is_requested(self,obj):
		is_requested = self.context.get('is_requested')
		return is_requested
	




class AssessmentAttemptSerializer(serializers.ModelSerializer):
	class Meta:
		model = AssessmentAttempt
		fields = [ 'id','attempt_number', 'completion_time','completed_date','complete_percent']



# Update the data structure

class AssessmentSerializer(serializers.ModelSerializer):
	images = serializers.SerializerMethodField()
	videos = serializers.SerializerMethodField()
	best_student_record = serializers.SerializerMethodField()
	exercise = serializers.SerializerMethodField()
	# exercise_id = serializers.CharField(source='exercise.id', read_only=True)
	class Meta:
		model = Assesments
		fields =['id','name','completion_time','exercise','repetitions','sets','weight','results','notes','youtube_link','next_assessment_date','images','videos','best_student_record']
	def get_exercise(self,obj):
		exercise_id=obj.exercise.id
		print(exercise_id)
		exercise=SubExercise.objects.filter(id=exercise_id).values()
		data=exercise[0]
		if exercise:
			images = data['images']
			print("before changes",type(images),images)
			videos = data['videos']
			print("before changes",type(videos),videos)

			if images:
				changed_images=json.loads(data['images'].replace("'", "\""))
				data['images']=changed_images
				print("After changes",type(images),images)
			if videos:
				changes_videos=json.loads(data['videos'].replace("'", "\""))
				data['videos']=changes_videos
				# videos=data['videos'].strip("[]").replace("'", "").split(", ")
				print("After changes",type(videos),videos)
			
			return data
		
		else:
			return {}
	def get_images(self, obj):
		images_string = obj.images
		if images_string:
			images_array = images_string.strip("[]").replace("'", "").split(", ")
		else:
			images_array = []
		return images_array

	def get_videos(self, obj):
		videos_string = obj.videos
		if videos_string:
			videos_array = videos_string.strip("[]").replace("'", "").split(", ")
		else:
			videos_array = []
		return videos_array
	
	def get_best_student_record(self, obj):
		student_assessment_obj = StudentAssessment.objects.filter(assessment=obj)
		best_attempts = {}
		if student_assessment_obj:
			for sa_obj in student_assessment_obj:
				best_attempt = AssessmentAttempt.objects.filter(assessment=sa_obj).order_by('user').values('user_id', 'user__full_name','attempt_number','completed_date').annotate(best_completion_time=Min('completion_time'))
				for attempt in best_attempt:
					user_id = attempt['user_id']
					username = attempt['user__full_name']
					attempt_number = attempt['attempt_number']
					best_completion_time = attempt['best_completion_time']
					completed_date = attempt['completed_date']
					if best_completion_time is not None and best_completion_time.total_seconds() > 10:
						if user_id not in best_attempts or best_completion_time < best_attempts[user_id].get('completion_time', timedelta.max):
							best_attempts[user_id] = {'user_id': user_id, 'name': username, 'completion_time': best_completion_time,'attempt_number':attempt_number,'completed_date':completed_date}
			
			sorted_records = sorted(best_attempts.values(), key=lambda x: x['completion_time'])
			return sorted_records
		else:
			return []

class GetIdAssessmentSerializer(serializers.ModelSerializer):
	images = serializers.SerializerMethodField()
	videos = serializers.SerializerMethodField()
	best_student_record = serializers.SerializerMethodField()
	exercise = serializers.SerializerMethodField()
	exercise_name = serializers.SerializerMethodField()
	# exercise_id = serializers.CharField(source='exercise.id', read_only=True)
	class Meta:
		model = Assesments
		fields =['id','name','completion_time','exercise','exercise_name','repetitions','sets','weight','results','notes','youtube_link','next_assessment_date','images','videos','best_student_record']
	def get_exercise(self,obj):
		exercise_id=obj.exercise.id
		print(exercise_id)
		exercise=SubExercise.objects.filter(id=exercise_id)
		if exercise:
			return exercise.values()[0]['id']
		
		else:
			return {}
	def get_exercise_name(self,obj):
		exercise_name=obj.exercise.name
		print(exercise_name)
		exercise=SubExercise.objects.filter(name=exercise_name)
		if exercise:
			return exercise.values()[0]['name']
		
		else:
			return {}
	def get_images(self, obj):
		images_string = obj.images
		if images_string:
			images_array = images_string.strip("[]").replace("'", "").split(", ")
		else:
			images_array = []
		return images_array

	def get_videos(self, obj):
		videos_string = obj.videos
		if videos_string:
			videos_array = videos_string.strip("[]").replace("'", "").split(", ")
		else:
			videos_array = []
		return videos_array
	
	def get_best_student_record(self, obj):
		student_assessment_obj = StudentAssessment.objects.filter(assessment=obj)
		best_attempts = {}
		if student_assessment_obj:
			for sa_obj in student_assessment_obj:
				best_attempt = AssessmentAttempt.objects.filter(assessment=sa_obj).order_by('user').values('user_id', 'user__full_name','attempt_number','completed_date').annotate(best_completion_time=Min('completion_time'))
				for attempt in best_attempt:
					user_id = attempt['user_id']
					username = attempt['user__full_name']
					attempt_number = attempt['attempt_number']
					best_completion_time = attempt['best_completion_time']
					completed_date = attempt['completed_date']
					if best_completion_time is not None and best_completion_time.total_seconds() > 10:
						if user_id not in best_attempts or best_completion_time < best_attempts[user_id].get('completion_time', timedelta.max):
							best_attempts[user_id] = {'user_id': user_id, 'name': username, 'completion_time': best_completion_time,'attempt_number':attempt_number,'completed_date':completed_date}
			
			sorted_records = sorted(best_attempts.values(), key=lambda x: x['completion_time'])
			return sorted_records
		else:
			return []


class StudentAssessmentSerializer(serializers.ModelSerializer):
	assessment = AssessmentSerializer()
	assessment_reports = serializers.SerializerMethodField(source='get_assessment_reports')
	class Meta:
		model = StudentAssessment
		fields = [ 'id','assessment', 'created_at','assessment_progress','assessment_reports']
	

	def get_assessment_reports(self, obj):
		assessment_attempt_obj = AssessmentAttempt.objects.filter(assessment=obj).order_by('attempt_number')
		if assessment_attempt_obj:
			return AssessmentAttemptSerializer(assessment_attempt_obj,many=True).data
		else:
			return []

class GetIdStudentAssessmentSerializer(serializers.ModelSerializer):
	assessment = GetIdAssessmentSerializer()
	assessment_reports = serializers.SerializerMethodField(source='get_assessment_reports')
	class Meta:
		model = StudentAssessment
		fields = [ 'id','assessment', 'created_at','assessment_progress','assessment_reports']
	

	def get_assessment_reports(self, obj):
		assessment_attempt_obj = AssessmentAttempt.objects.filter(assessment=obj).order_by('attempt_number')
		if assessment_attempt_obj:
			return AssessmentAttemptSerializer(assessment_attempt_obj,many=True).data
		else:
			return []


import json
class StudentSerializer(serializers.ModelSerializer):
	name = serializers.CharField(source='app_user.full_name', read_only=True)
	image = serializers.CharField(source='app_user.image', read_only=True)
	age = serializers.CharField(source='app_user.age', read_only=True)
	gender = serializers.CharField(source='app_user.gender', read_only=True)
	fitness_level = serializers.CharField(source='app_user.fitness_level', read_only=True)
	focus_area = serializers.SerializerMethodField(read_only=True)
	main_goals = serializers.SerializerMethodField(read_only=True)
	medical_conditions = serializers.SerializerMethodField(read_only=True)
	any_allergies = serializers.SerializerMethodField(read_only=True)
	assessments = serializers.SerializerMethodField()
	workout_plans = serializers.SerializerMethodField()

	class Meta:
		model = Students
		fields = ['id', 'name', 'image','age','gender','fitness_level','focus_area','main_goals', 'medical_conditions','any_allergies','assessments','workout_plans','app_user']
	
	def get_focus_area(self, obj):
		return self._safe_json_load(obj.app_user.focus_area)

	def get_main_goals(self, obj):
		return self._safe_json_load(obj.app_user.main_goal)

	def get_medical_conditions(self, obj):
		return self._safe_json_load(obj.app_user.medical_condition)

	def get_any_allergies(self, obj):
		return self._safe_json_load(obj.app_user.allergies_exclusions)

	def _safe_json_load(self, value):
		"""Safely load a JSON string or return an empty list."""
		if value:
			try:
				return json.loads(value)
			except (json.JSONDecodeError, TypeError):
				return []  # Return an empty list on error
		return []
	def get_assessments(self, obj):
		assessments = obj.studentassessment_set.filter(end_date__isnull=True).order_by('-id')  #related name is 'studentassessment_set'
		serializer = GetIdStudentAssessmentSerializer(assessments, many=True)
		return serializer.data
	
	def get_workout_plans(self, obj):
		workout_plans = obj.studentworkoutplan_set.filter(end_date__isnull=True).order_by('-id')  # related name is 'studentworkoutplan_set'
		serializer = StudentWorkOutSerializer(workout_plans, many=True)
		return serializer.data





class AppTrainerFriendSerializer(serializers.ModelSerializer):
	friend_status = serializers.SerializerMethodField(source='get_friend_status')
	class Meta:
		model = Trainer
		fields = ['id', 'full_name','image','gender','age','friend_status']
	
	def get_friend_status(self,obj):
		login_user = self.context.get('login_user')
		# friend_status = FriendRequest.objects.filter(
		# (models.Q(from_user=login_user, to_user=obj) | models.Q(from_user=obj, to_user=login_user)),
		# accepted=True
		# ).exists()
		friend_status = TrainerFriends.objects.filter(
		(models.Q(from_user=login_user, to_user=obj) | models.Q(from_user=obj, to_user=login_user))
		)
		if not friend_status:
			friend_status = None
		else:
			for friends in friend_status:
				if friends.accepted==True:
					friend_status = 'friends'
				elif friends.accepted == False:
					friend_status = 'requested'
		return friend_status


class SentFriendListSerializer(serializers.ModelSerializer):
	to_user = AppTrainerFriendSerializer()

	class Meta:
		model = TrainerFriends
		fields = ['id', 'to_user', 'accepted']


	
class ReceivedFriendListSerializer(serializers.ModelSerializer):
	from_user = AppTrainerFriendSerializer()

	class Meta:
		model = TrainerFriends
		fields = ['id', 'from_user', 'accepted']


class ExerciseSerializer(serializers.ModelSerializer):
	class Meta:
		model = Exercise
		fields = ['id', 'name', 'description', 'image']

	

class PlanExerciseSerializer(serializers.ModelSerializer):
		body_part = serializers.SerializerMethodField()
		exercise_data = serializers.SerializerMethodField()
		# workout_day_name = serializers.SerializerMethodField()  
		class Meta:
			model = PlanExercise
			fields = ['id','body_part', 'exercise_data', 'created_at', 'updated_at', 'end_date']

		def get_body_part(self, obj):
			body_part_string = obj.body_part
			if body_part_string:
				body_part = body_part_string.strip("[]").replace("'", "").split(", ")
			else:
				body_part = []
			return body_part

		def get_exercise_data(self, obj):
			work_type = self.context.get('work_type', 'public')
			workout_day_name = obj.day.name
			print(f"Workout Day Name in get_exercise_data: {workout_day_name}")  # Debugging print statement

			exercise_data = []
			seen_exercises = set()  # To track unique exercises based on unique fields
			print(obj.exercise_data)
			for exercise_entry in obj.exercise_data:
				# print(exercise_entry)
				exercise_id = exercise_entry['exercise_id'] if 'exercise_id' in exercise_entry else None
			   
				try:
					exercise = SubExercise.objects.filter(id=exercise_id).first()
					check_completed=UserIsExerciseWorkout.objects.filter(sub_exercise=exercise,exercise=obj,workout_day=workout_day_name,workout_type=work_type)
					if check_completed:
						is_completed=True 
					else:
						is_completed=False 
					if exercise:
						if exercise.images:
							exercise_images = ast.literal_eval(exercise.images)
						else:
							exercise_images=None
						if exercise.videos:
							exercise_videos = ast.literal_eval(exercise.videos)
						else:
							exercise_videos=None

						# Define unique data to check for duplicates
						unique_data = (
							exercise_entry['sets'],
							exercise_entry['reps'],
							exercise_entry.get('weight', None),
							exercise.id,
							exercise.name,
							exercise.description,
							exercise_images[0] if exercise_images else None,
						)

						# Add to exercise_data only if unique
						if unique_data not in seen_exercises:
							seen_exercises.add(unique_data)  # Mark as seen
							exercise_data.append({
								'sets': exercise_entry['sets'],
								'reps': exercise_entry['reps'],
								'weight': exercise_entry.get('weight', None),
								'exercise_id': exercise.id,
								'exercise_name': exercise.name,
								'exercise_description': exercise.description,
								'is_completed': is_completed,
								'exercise_image': exercise_images[0] if exercise_images else None,
								'exercise_video': exercise_videos,
							})

				except SubExercise.DoesNotExist:
					# Handle case where exercise doesn't exist
					exercise_data.append({
						'sets': exercise_entry['sets'],
						'reps': exercise_entry['reps'],
						'weight': exercise_entry.get('weight', None),
						'exercise_id': exercise_id,
						'exercise_name': None,
						'exercise_description': None,
						'exercise_image': None,
						'exercise_video': None,
					})

			return exercise_data
class WorkoutDaySerializer(serializers.ModelSerializer):
	exercises = PlanExerciseSerializer(many=True, source='planexercise_set')

	class Meta:
		model = WorkoutDay
		fields = ['name', 'exercises']

class WorkoutWeekSerializer(serializers.ModelSerializer):
	days = WorkoutDaySerializer(many=True, source='workoutday_set')

	class Meta:
		model = WorkoutWeek
		fields = ['week_number', 'days']

class WorkoutPlanSerializer(serializers.ModelSerializer):
	weeks = WorkoutWeekSerializer(many=True, source='workoutweek_set')

	class Meta:
		model = WorkoutPlan
		fields = '__all__'
	

class WorkoutPlanListSerializer(serializers.ModelSerializer):
	class Meta:
		model = WorkoutPlan
		fields = '__all__'


class StudentWorkOutSerializer(serializers.ModelSerializer):
	workout = WorkoutPlanSerializer()
	class Meta:
		model = StudentWorkOutPlan
		fields = [ 'id','workout', 'created_at','workout_progress']