""" Analytics Report Model - Aggregated analytics snapshots. """ from datetime import datetime, date from sqlalchemy import Column, Integer, Float, String, DateTime, Date, JSON, Text from app.core.database import Base class AnalyticsReport(Base): """ Stores aggregated analytics reports (daily, weekly, monthly). """ __tablename__ = "analytics_reports" id = Column(Integer, primary_key=True, index=True) # Report type and period report_type = Column(String(20), nullable=False, index=True) # daily, weekly, monthly period_start = Column(Date, nullable=False, index=True) period_end = Column(Date, nullable=False) platform = Column(String(50), nullable=True) # null = all platforms # Aggregated metrics total_posts = Column(Integer, default=0) total_impressions = Column(Integer, default=0) total_reach = Column(Integer, default=0) total_engagements = Column(Integer, default=0) total_likes = Column(Integer, default=0) total_comments = Column(Integer, default=0) total_shares = Column(Integer, default=0) # Calculated averages avg_engagement_rate = Column(Float, default=0.0) avg_impressions_per_post = Column(Float, default=0.0) avg_engagements_per_post = Column(Float, default=0.0) # Comparison with previous period posts_change_pct = Column(Float, nullable=True) engagement_change_pct = Column(Float, nullable=True) impressions_change_pct = Column(Float, nullable=True) # Top performing data (JSON) top_posts = Column(JSON, nullable=True) # [{"post_id": 1, "content": "...", "engagement_rate": 5.2, "platform": "x"}] best_times = Column(JSON, nullable=True) # [{"day": 1, "hour": 12, "avg_engagement": 4.5}] content_performance = Column(JSON, nullable=True) # {"tip": {"posts": 10, "avg_engagement": 3.2}, "product": {...}} platform_breakdown = Column(JSON, nullable=True) # {"x": {"posts": 20, "engagement": 150}, "threads": {...}} # Report content for Telegram summary_text = Column(Text, nullable=True) # Metadata generated_at = Column(DateTime, default=datetime.utcnow) sent_to_telegram = Column(DateTime, nullable=True) def to_dict(self): return { "id": self.id, "report_type": self.report_type, "period_start": self.period_start.isoformat() if self.period_start else None, "period_end": self.period_end.isoformat() if self.period_end else None, "platform": self.platform, "total_posts": self.total_posts, "total_impressions": self.total_impressions, "total_reach": self.total_reach, "total_engagements": self.total_engagements, "avg_engagement_rate": round(self.avg_engagement_rate, 2), "avg_impressions_per_post": round(self.avg_impressions_per_post, 1), "posts_change_pct": round(self.posts_change_pct, 1) if self.posts_change_pct else None, "engagement_change_pct": round(self.engagement_change_pct, 1) if self.engagement_change_pct else None, "top_posts": self.top_posts, "best_times": self.best_times, "content_performance": self.content_performance, "platform_breakdown": self.platform_breakdown, "generated_at": self.generated_at.isoformat() if self.generated_at else None } def generate_telegram_summary(self) -> str: """Generate formatted summary for Telegram.""" lines = [ f"📊 *Reporte {self.report_type.title()}*", f"📅 {self.period_start} - {self.period_end}", "", f"📝 Posts publicados: *{self.total_posts}*", f"👁 Impresiones: *{self.total_impressions:,}*", f"💬 Interacciones: *{self.total_engagements:,}*", f"📈 Engagement rate: *{self.avg_engagement_rate:.2f}%*", ] if self.engagement_change_pct is not None: emoji = "📈" if self.engagement_change_pct > 0 else "📉" lines.append(f"{emoji} vs anterior: *{self.engagement_change_pct:+.1f}%*") if self.platform_breakdown: lines.append("") lines.append("*Por plataforma:*") for platform, data in self.platform_breakdown.items(): lines.append(f" • {platform}: {data.get('posts', 0)} posts, {data.get('engagements', 0)} interacciones") if self.top_posts and len(self.top_posts) > 0: lines.append("") lines.append("*Top 3 posts:*") for i, post in enumerate(self.top_posts[:3], 1): content = post.get('content', '')[:50] + "..." if len(post.get('content', '')) > 50 else post.get('content', '') lines.append(f" {i}. {content} ({post.get('engagement_rate', 0):.1f}%)") self.summary_text = "\n".join(lines) return self.summary_text