package handlers import ( "fmt" "gestion/db" "gestion/models" "net/http" "github.com/gin-gonic/gin" ) var weekdayNames = []string{"Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"} // GetAdminStats returns aggregated order & product statistics for the admin dashboard. func GetAdminStats(c *gin.Context) { database := c.MustGet("database").(*db.Database) gdb := database.GDB // ── Commandes par jour de la semaine (all time, non annulées) ────────────── var wdRows []models.WeekdayRow gdb.Raw(` SELECT EXTRACT(DOW FROM created_at)::int AS dow, COUNT(*) AS count FROM commandes WHERE status != 'cancelled' GROUP BY dow ORDER BY dow `).Scan(&wdRows) byWeekday := make([]gin.H, 7) wdMap := make(map[int]int, len(wdRows)) for _, r := range wdRows { wdMap[r.DOW] = r.Count } peakCount, peakWeekday := 0, "" for i := 0; i < 7; i++ { cnt := wdMap[i] byWeekday[i] = gin.H{"weekday": weekdayNames[i], "count": cnt} if cnt > peakCount { peakCount = cnt peakWeekday = weekdayNames[i] } } // ── Commandes par jour sur 30 jours ─────────────────────────────────────── var dayRows []models.DayRow gdb.Raw(` SELECT DATE(created_at) AS day, COUNT(*) AS count FROM commandes WHERE created_at >= NOW() - INTERVAL '30 days' AND status != 'cancelled' GROUP BY DATE(created_at) ORDER BY day `).Scan(&dayRows) byDay := make([]gin.H, len(dayRows)) for i, r := range dayRows { byDay[i] = gin.H{ "day": r.Day.Format("2006-01-02"), "label": r.Day.Format("02/01"), "count": r.Count, } } // ── Revenus par jour sur 30 jours (commandes approuvées) ───────────────── var dayRevRows []models.DayRevenueRow gdb.Raw(` SELECT DATE(created_at) AS day, COALESCE(SUM(total_prix), 0) AS revenue FROM commandes WHERE created_at >= NOW() - INTERVAL '30 days' AND status = 'approved' GROUP BY DATE(created_at) ORDER BY day `).Scan(&dayRevRows) byDayRevenue := make([]gin.H, len(dayRevRows)) for i, r := range dayRevRows { byDayRevenue[i] = gin.H{ "day": r.Day.Format("2006-01-02"), "label": r.Day.Format("02/01"), "revenue": r.Revenue, } } // ── Commandes & revenus par heure (all time, non annulées) ─────────────── var hourRows []models.HourRow gdb.Raw(` SELECT EXTRACT(HOUR FROM created_at)::int AS hour, COUNT(*) AS count, COALESCE(SUM(total_prix), 0) AS revenue FROM commandes WHERE status != 'cancelled' GROUP BY hour ORDER BY hour `).Scan(&hourRows) hourMap := make(map[int]models.HourRow, len(hourRows)) for _, r := range hourRows { hourMap[r.Hour] = r } byHour := make([]gin.H, 24) for h := 0; h < 24; h++ { r := hourMap[h] byHour[h] = gin.H{ "hour": h, "label": fmt.Sprintf("%02dh", h), "count": r.Count, "revenue": r.Revenue, } } // ── Top produits (quantité vendue, commandes terminées) ─────────────────── var prodRows []models.ProductRow gdb.Raw(` SELECT ci.product_id, ci.produit AS name, SUM(ci.quantite) AS total_quantity, COUNT(DISTINCT ci.command_id) AS order_count, SUM(ci.prix * ci.quantite) AS revenue, COALESCE(p.category, '') AS category, COALESCE(cat.color, '#7c3aed') AS category_color FROM command_items ci JOIN commandes c ON c.id = ci.command_id LEFT JOIN products p ON p.id = ci.product_id LEFT JOIN categories cat ON cat.name = p.category WHERE c.status != 'cancelled' GROUP BY ci.product_id, ci.produit, p.category, cat.color ORDER BY total_quantity DESC LIMIT 15 `).Scan(&prodRows) topProducts := make([]gin.H, len(prodRows)) topProductName := "" for i, r := range prodRows { topProducts[i] = gin.H{ "product_id": r.ProductID, "name": r.Name, "quantity": r.Quantity, "order_count": r.OrderCount, "revenue": r.Revenue, "category": r.Category, "category_color": r.CategoryColor, } if i == 0 { topProductName = r.Name } } // ── Résumé global ───────────────────────────────────────────────────────── var totalOrders int64 var totalRevenue float64 gdb.Raw(`SELECT COUNT(*) FROM commandes WHERE status != 'cancelled'`).Scan(&totalOrders) gdb.Raw(`SELECT COALESCE(SUM(total_prix), 0) FROM commandes WHERE status = 'approved'`).Scan(&totalRevenue) avgPerDay := 0.0 if totalOrders > 0 { // average over the last 30 days with data var activeDays int64 gdb.Raw(` SELECT COUNT(DISTINCT DATE(created_at)) FROM commandes WHERE created_at >= NOW() - INTERVAL '30 days' AND status != 'cancelled' `).Scan(&activeDays) if activeDays > 0 { var last30Count int64 gdb.Raw(` SELECT COUNT(*) FROM commandes WHERE created_at >= NOW() - INTERVAL '30 days' AND status != 'cancelled' `).Scan(&last30Count) avgPerDay = float64(last30Count) / float64(activeDays) } } c.JSON(http.StatusOK, gin.H{ "summary": gin.H{ "total_orders": totalOrders, "total_revenue": totalRevenue, "peak_weekday": peakWeekday, "top_product": topProductName, "avg_per_day": avgPerDay, }, "by_weekday": byWeekday, "by_day_30": byDay, "by_day_revenue": byDayRevenue, "by_hour": byHour, "top_products": topProducts, }) }