"""Comprehensive analytics data from all DB tables with optional filters.""" from __future__ import annotations from datetime import datetime, timezone from typing import Any, Optional from app.db import fetch_all, fetch_one def _safe_count(table: str, where: str = "", params: tuple = ()) -> int: try: clause = f" WHERE {where}" if where else "" row = fetch_one(f"SELECT COUNT(*) AS c FROM {table}{clause}", params or None) return int(row["c"]) if row else 0 except Exception: return 0 def _iso_rows(rows: list) -> list: for row in rows: for key, val in list(row.items()): if hasattr(val, "isoformat"): row[key] = val.isoformat() elif val is not None and type(val).__name__ == "Decimal": row[key] = float(val) return rows def collect_analytics(filters: Optional[dict[str, Any]] = None) -> dict[str, Any]: f = filters or {} chain = f.get("chain") or None province = f.get("province") or None stage = f.get("stage") or None agent = f.get("agent") or None days = int(f.get("days") or 90) data: dict[str, Any] = { "generated_at": datetime.now(timezone.utc).isoformat(), "filters": f, } data["kpis"] = { "clients_total": _safe_count("clients"), "clients_active": _safe_count("clients", "stage = 'active'"), "deals_total": _safe_count("deals"), "pipeline_eur": float( (fetch_one("SELECT COALESCE(SUM(value),0) AS t FROM deals WHERE stage NOT IN ('won','lost')") or {}).get("t", 0) ), "supermarkets": _safe_count("supermarkets"), "wholesalers": _safe_count("wholesalers"), "crm_partnerships": _safe_count("supermarkets", "partnership_status = 'active'"), "rss_items": _safe_count("rss_items"), "rss_bookmarks": _safe_count("rss_bookmarks"), "agent_events": _safe_count("agent_events"), "pending_approvals": _safe_count("agent_events", "status = 'needs_approval'"), "promo_campaigns": _safe_count("promo_campaigns", "status = 'active'"), "contacts_supermarket": _safe_count("supermarket_contacts"), "contacts_wholesaler": _safe_count("wholesaler_contacts"), "nas_docs": _safe_count("document_analytics"), } try: data["clients_by_stage"] = fetch_all( "SELECT stage, COUNT(*) AS cnt FROM clients GROUP BY stage ORDER BY cnt DESC" ) except Exception: data["clients_by_stage"] = [] try: data["deals_by_stage"] = fetch_all( "SELECT stage, COUNT(*) AS cnt, COALESCE(SUM(value),0) AS total FROM deals GROUP BY stage ORDER BY cnt DESC" ) except Exception: data["deals_by_stage"] = [] try: data["events_by_agent"] = fetch_all( """SELECT agent_name, COUNT(*) AS cnt FROM agent_events WHERE created_at >= NOW() - INTERVAL '%s days' GROUP BY agent_name ORDER BY cnt DESC LIMIT 20""" % days ) except Exception: data["events_by_agent"] = [] store_where, store_params = [], [] if chain: store_where.append("chain = %s") store_params.append(chain) if province: store_where.append("province = %s") store_params.append(province) sw = (" WHERE " + " AND ".join(store_where)) if store_where else "" try: data["supermarkets_by_chain"] = fetch_all( f"SELECT chain, COUNT(*) AS cnt FROM supermarkets{sw} GROUP BY chain ORDER BY cnt DESC LIMIT 15", tuple(store_params) if store_params else None, ) except Exception: data["supermarkets_by_chain"] = [] try: data["supermarkets_by_province"] = fetch_all( f"SELECT province, COUNT(*) AS cnt FROM supermarkets{sw} AND province IS NOT NULL GROUP BY province ORDER BY cnt DESC LIMIT 12" if store_where else "SELECT province, COUNT(*) AS cnt FROM supermarkets WHERE province IS NOT NULL GROUP BY province ORDER BY cnt DESC LIMIT 12" ) except Exception: data["supermarkets_by_province"] = [] try: data["partnership_breakdown"] = fetch_all( "SELECT COALESCE(partnership_status,'none') AS status, COUNT(*) AS cnt FROM supermarkets GROUP BY partnership_status ORDER BY cnt DESC" ) except Exception: data["partnership_breakdown"] = [] try: data["wholesalers_by_province"] = fetch_all( "SELECT province, COUNT(*) AS cnt FROM wholesalers WHERE province IS NOT NULL GROUP BY province ORDER BY cnt DESC LIMIT 12" ) except Exception: data["wholesalers_by_province"] = [] try: data["rss_by_category"] = fetch_all( """SELECT f.category, COUNT(i.id) AS cnt FROM rss_items i JOIN rss_feeds f ON f.id = i.feed_id GROUP BY f.category ORDER BY cnt DESC""" ) except Exception: data["rss_by_category"] = [] try: data["events_timeline"] = fetch_all( """SELECT DATE(created_at) AS day, COUNT(*) AS cnt FROM agent_events WHERE created_at >= NOW() - INTERVAL '%s days' GROUP BY DATE(created_at) ORDER BY day ASC""" % days ) except Exception: data["events_timeline"] = [] try: data["milestones_by_status"] = fetch_all( "SELECT status, COUNT(*) AS cnt FROM sales_milestones GROUP BY status ORDER BY cnt DESC" ) except Exception: data["milestones_by_status"] = [] try: data["top_opportunities"] = fetch_all( """SELECT s.chain, s.city, ros.halal_opportunity_score FROM retail_opportunity_scores ros JOIN supermarkets s ON s.id = ros.supermarket_id ORDER BY ros.halal_opportunity_score DESC LIMIT 10""" ) except Exception: data["top_opportunities"] = [] try: data["sentiment_distribution"] = fetch_all( "SELECT sentiment_label, COUNT(*) AS cnt FROM document_analytics GROUP BY sentiment_label" ) except Exception: data["sentiment_distribution"] = [] try: data["top_words"] = fetch_all( """SELECT lemma, SUM(count) AS total FROM document_word_counts WHERE NOT is_stopword GROUP BY lemma ORDER BY total DESC LIMIT 15""" ) except Exception: data["top_words"] = [] try: data["promo_by_chain"] = fetch_all( "SELECT chain, COUNT(*) AS cnt FROM promo_campaigns WHERE status = 'active' GROUP BY chain ORDER BY cnt DESC" ) except Exception: data["promo_by_chain"] = [] deal_where = "" deal_params: tuple = () if stage: deal_where = " WHERE stage = %s" deal_params = (stage,) try: data["recent_deals"] = fetch_all( f"SELECT title, stage, value, updated_at FROM deals{deal_where} ORDER BY updated_at DESC LIMIT 10", deal_params or None, ) except Exception: data["recent_deals"] = [] agent_where = f" WHERE created_at >= NOW() - INTERVAL '{days} days'" if agent: agent_where += " AND agent_name = %s" try: data["recent_events"] = fetch_all( f"""SELECT agent_name, event_type, title, status, created_at FROM agent_events {agent_where} ORDER BY created_at DESC LIMIT 25""", (agent,), ) except Exception: data["recent_events"] = [] else: try: data["recent_events"] = fetch_all( f"""SELECT agent_name, event_type, title, status, created_at FROM agent_events {agent_where} ORDER BY created_at DESC LIMIT 25""" ) except Exception: data["recent_events"] = [] try: data["filter_meta"] = { "chains": fetch_all("SELECT DISTINCT chain FROM supermarkets WHERE chain IS NOT NULL ORDER BY chain"), "provinces": fetch_all("SELECT DISTINCT province FROM supermarkets WHERE province IS NOT NULL ORDER BY province"), "client_stages": fetch_all("SELECT DISTINCT stage FROM clients ORDER BY stage"), "deal_stages": fetch_all("SELECT DISTINCT stage FROM deals ORDER BY stage"), "agents": fetch_all("SELECT DISTINCT agent_name FROM agent_events ORDER BY agent_name"), } except Exception: data["filter_meta"] = {} for key in ( "clients_by_stage", "deals_by_stage", "events_by_agent", "supermarkets_by_chain", "supermarkets_by_province", "partnership_breakdown", "wholesalers_by_province", "rss_by_category", "events_timeline", "milestones_by_status", "top_opportunities", "sentiment_distribution", "top_words", "promo_by_chain", "recent_deals", "recent_events", ): if isinstance(data.get(key), list): data[key] = _iso_rows(data[key]) return data