from collections import defaultdict
from datetime import date


class Stats:
    def __init__(self, db_connection_method):
        self.execute = db_connection_method

    def get_stats_from_topsets(self, topsets):
        if not topsets:
            return []

        # Extract necessary fields
        workout_ids = [t["WorkoutId"] for t in topsets if t["WorkoutId"]]
        person_ids = [t["PersonId"] for t in topsets if t["PersonId"]]
        start_dates = [t["StartDate"] for t in topsets if t["StartDate"]]
        exercise_ids = [t["ExerciseId"] for t in topsets if t["ExerciseId"]]

        workout_count = len(set(workout_ids))
        people_count = len(set(person_ids))
        total_sets = len(topsets)
        exercise_count = len(set(exercise_ids))

        # Group sets by workout and exercise
        sets_per_exercise_per_workout = defaultdict(lambda: defaultdict(int))
        for t in topsets:
            if t["WorkoutId"] and t["ExerciseId"]:
                sets_per_exercise_per_workout[t["WorkoutId"]][t["ExerciseId"]] += 1

        # Calculate the average sets per exercise across all workouts
        total_sets_per_exercise = []
        for workout_exercises in sets_per_exercise_per_workout.values():
            total_sets_per_exercise.extend(workout_exercises.values())

        average_sets_per_exercise = round(sum(total_sets_per_exercise) / len(total_sets_per_exercise), 1) if total_sets_per_exercise else 0

        # Group exercises by workout
        exercises_by_workout = defaultdict(set)
        for t in topsets:
            if t["WorkoutId"] and t["ExerciseId"]:
                exercises_by_workout[t["WorkoutId"]].add(t["ExerciseId"])

        # Calculate average exercises per workout
        average_exercises_per_workout = round(
            sum(len(exercises) for exercises in exercises_by_workout.values()) / workout_count, 1
        ) if workout_count > 0 else 0

        # Stats
        stats = [
            {"Text": "Total Workouts", "Value": workout_count},
            {"Text": "Total Sets", "Value": total_sets},
            {"Text": "Total Exercises", "Value": exercise_count},
            {"Text": "Average Sets Per Exercise", "Value": average_sets_per_exercise},
            {"Text": "Average Exercises Per Workout", "Value": average_exercises_per_workout},
        ]

        if people_count > 1:
            stats.append({"Text": "People Tracked", "Value": people_count})

        if workout_count > 0:
            first_workout_date = min(start_dates)
            last_workout_date = max(start_dates)
            current_date = date.today()

            stats.append({"Text": "Days Since First Workout",
                          "Value": (current_date - first_workout_date).days})

            if workout_count >= 2:
                stats.append({"Text": "Days Since Last Workout",
                              "Value": (current_date - last_workout_date).days})

                average_sets_per_workout = round(total_sets / workout_count, 1)
                stats.append({"Text": "Average Sets Per Workout",
                              "Value": average_sets_per_workout})

                training_duration = last_workout_date - first_workout_date
                if training_duration.days > 0:
                    average_workouts_per_week = round(
                        workout_count / (training_duration.days / 7), 1)
                    stats.append({"Text": "Average Workouts Per Week",
                                  "Value": average_workouts_per_week})

        return stats

    def fetch_stats_for_person(self, person_id):
        query = """
        SELECT
            t.workout_id AS "WorkoutId",
            w.person_id AS "PersonId",
            w.start_date AS "StartDate",
            e.exercise_id AS "ExerciseId"
        FROM
            topset t
            JOIN workout w ON t.workout_id = w.workout_id
            JOIN person p ON w.person_id = p.person_id
            JOIN exercise e ON t.exercise_id = e.exercise_id
        WHERE p.person_id = %s
        """
        workouts_data = self.execute(query, [person_id])

        person_stats = self.get_stats_from_topsets(workouts_data)
        return person_stats

    def fetch_all_stats(self):
        query = """
        SELECT
            t.workout_id AS "WorkoutId",
            w.person_id AS "PersonId",
            w.start_date AS "StartDate",
            e.exercise_id AS "ExerciseId"
        FROM
            topset t
            JOIN workout w ON t.workout_id = w.workout_id
            JOIN person p ON w.person_id = p.person_id
            JOIN exercise e ON t.exercise_id = e.exercise_id
        """
        workouts_data = self.execute(query, [])

        person_stats = self.get_stats_from_topsets(workouts_data)
        return person_stats
