import os import sys from pathlib import Path from datetime import datetime, timezone, timedelta # Add the server root to the Python path server_root = Path(__file__).resolve().parent.parent sys.path.append(str(server_root)) from firebase_admin import firestore from src.db.firebase import get_firebase_db from src.utils.logger import setup_logger logger = setup_logger(__name__) def recalculate_analytics(): """ Recalculates all KPI fields for every user by iterating through their notes. """ db = get_firebase_db() if not db: logger.error("Database not initialized") return logger.info("Starting comprehensive analytics recalculation...") users_ref = db.collection('users') notes_ref = db.collection('notes') analytics_ref = db.collection('analytics') try: users = users_ref.stream() migrated_count = 0 now = datetime.now(timezone.utc) week_ago = now - timedelta(days=7) current_month = now.month current_year = now.year for user_doc in users: user_id = user_doc.id logger.info(f"Processing user: {user_id}") # Fetch all notes for this user user_notes = list(notes_ref.where('userId', '==', user_id).stream()) # --- Initialize KPI Counters --- notes_count = len(user_notes) category_count = {} favorite_notes_count = 0 total_key_points = 0 total_video_duration_seconds = 0 this_week_videos = 0 this_month_saved_hours = 0.0 # For streak calculation note_dates = set() for note_doc in user_notes: data = note_doc.to_dict() # Categories categories = [] if 'category' in data: cat_data = data['category'] if isinstance(cat_data, list): categories = cat_data elif isinstance(cat_data, str): categories = [cat_data] elif 'video_categories' in data and isinstance(data['video_categories'], list): categories = data['video_categories'] elif 'categories' in data and isinstance(data['categories'], list): categories = data['categories'] if 'Uncategorized' in categories: categories.remove('Uncategorized') if not categories: categories.append('Technology & AI') for cat in categories: category_count[cat] = category_count.get(cat, 0) + 1 # Favorites if data.get('isFavorite', False): favorite_notes_count += 1 # Key Points key_points = data.get('keyPoints', []) total_key_points += len(key_points) # Duration video_duration = data.get('videoDuration', data.get('video_duration', 0)) total_video_duration_seconds += video_duration # Dates (for streak, weekly, monthly stats) created_at = data.get('createdAt') if created_at: dt = created_at # Some data might have python datetimes if created directly if hasattr(created_at, 'timestamp'): # Handle Google Cloud Timestamp vs Python datetime dt_val = created_at # Store date string for streak calculation (YYYY-MM-DD) note_dates.add(dt.strftime('%Y-%m-%d')) # This week videos if dt >= week_ago: this_week_videos += 1 # This month saved hours (assuming videoDuration is the saved time roughly) if dt.month == current_month and dt.year == current_year: this_month_saved_hours += video_duration / 3600.0 # --- Finalize Aggregations --- total_minutes = total_video_duration_seconds // 60 total_saved_hours = total_video_duration_seconds / 3600.0 # Find favorite category favorite_category = 'None' if category_count: favorite_category = max(category_count.items(), key=lambda x: x[1])[0] # Calculate current streak current_streak = 0 check_date = now.date() # If they haven't posted today, check if they posted yesterday (streak is still alive) if check_date.strftime('%Y-%m-%d') not in note_dates: check_date = check_date - timedelta(days=1) while check_date.strftime('%Y-%m-%d') in note_dates: current_streak += 1 check_date -= timedelta(days=1) # Update analytics document analytics_data = { 'userId': user_id, 'notesCount': notes_count, 'categoryCount': category_count, 'favoriteCategory': favorite_category, 'favoriteNotesCount': favorite_notes_count, 'totalKeyPoints': total_key_points, 'totalMinutes': total_minutes, 'totalSavedHours': round(total_saved_hours, 2), 'thisWeekVideos': this_week_videos, 'thisMonthSavedHours': round(this_month_saved_hours, 2), 'currentStreak': current_streak, 'lastUpdated': firestore.SERVER_TIMESTAMP, } analytics_ref.document(user_id).set(analytics_data, merge=True) logger.info(f"Updated analytics for {user_id}: {notes_count} notes, {current_streak} streak.") migrated_count += 1 logger.info(f"Recalculation completed. Processed {migrated_count} users.") except Exception as e: logger.error(f"Error during recalculation: {e}", exc_info=True) if __name__ == "__main__": recalculate_analytics()