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["workout_id"] for t in topsets if t["workout_id"]]
        person_ids = [t["person_id"] for t in topsets if t["person_id"]]
        start_dates = [t["start_date"] for t in topsets if t["start_date"]]
        exercise_ids = [t["exercise_id"] for t in topsets if t["exercise_id"]]

        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["workout_id"] and t["exercise_id"]:
                sets_per_exercise_per_workout[t["workout_id"]][t["exercise_id"]] += 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["workout_id"] and t["exercise_id"]:
                exercises_by_workout[t["workout_id"]].add(t["exercise_id"])

        # 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": "Average Sets Per Exercise", "value": average_sets_per_exercise}
        ]

        if exercise_count > 1:
            stats.append({"text": "Total Exercises", "value": exercise_count})
            stats.append({"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(self, selected_people_ids=None, min_date=None, max_date=None, selected_exercise_ids=None):
        # Base query
        query = """
        SELECT
            t.workout_id,
            w.person_id,
            w.start_date,
            e.exercise_id
        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
        """

        # Parameters for the query
        params = []

        # Add optional filters
        conditions = []  # Collect conditions dynamically
        if selected_people_ids:
            placeholders = ", ".join(["%s"] * len(selected_people_ids))
            conditions.append(f"p.person_id IN ({placeholders})")
            params.extend(selected_people_ids)
        if min_date:
            conditions.append("w.start_date >= %s")
            params.append(min_date)
        if max_date:
            conditions.append("w.start_date <= %s")
            params.append(max_date)
        if selected_exercise_ids:
            placeholders = ", ".join(["%s"] * len(selected_exercise_ids))
            conditions.append(f"e.exercise_id IN ({placeholders})")
            params.extend(selected_exercise_ids)

        # Add conditions to the query
        if conditions:
            query += " WHERE " + " AND ".join(conditions)

        # Execute the query
        workouts_data = self.execute(query, params)

        # Generate stats from the retrieved data
        stats = self.get_stats_from_topsets(workouts_data)
        return stats
