Initial commit

This commit is contained in:
2026-05-13 19:42:49 -07:00
commit cfa01bd4ef
54 changed files with 11718 additions and 0 deletions

View File

@@ -0,0 +1,76 @@
package scheduler
import (
"fmt"
"time"
"veola/internal/models"
"veola/templates"
)
// PickBadge returns the highest-priority deal-quality badge that applies to
// an item, or an empty BadgeData if none match. Order:
// 1. All-time low
// 2. X% below 30-day avg (only when at least 10% below)
// 3. X% below target
func PickBadge(it models.Item, history []models.PricePoint, now time.Time) templates.BadgeData {
if it.BestPrice == nil {
return templates.BadgeData{}
}
best := *it.BestPrice
// 1. All-time low
if isAllTimeLow(best, history) {
return templates.BadgeData{Label: "All-time low", Class: "v-badge-low"}
}
// 2. X% below 30-day average
if avg, ok := windowedMean(history, now, 30*24*time.Hour); ok && best > 0 && avg > 0 {
pct := (avg - best) / avg * 100
if pct >= 10 {
return templates.BadgeData{
Label: fmt.Sprintf("%d%% below 30-day avg", int(pct+0.5)),
Class: "v-badge-avg",
}
}
}
// 3. X% below target
if it.TargetPrice != nil && *it.TargetPrice > 0 && best < *it.TargetPrice {
pct := (*it.TargetPrice - best) / *it.TargetPrice * 100
return templates.BadgeData{
Label: fmt.Sprintf("%d%% below target", int(pct+0.5)),
Class: "v-badge-target",
}
}
return templates.BadgeData{}
}
func isAllTimeLow(best float64, history []models.PricePoint) bool {
if len(history) == 0 {
return false
}
for _, p := range history {
if p.Price > 0 && p.Price < best {
return false
}
}
return true
}
func windowedMean(history []models.PricePoint, now time.Time, window time.Duration) (float64, bool) {
cutoff := now.Add(-window)
sum, n := 0.0, 0
for _, p := range history {
if p.PolledAt.Before(cutoff) {
continue
}
sum += p.Price
n++
}
if n == 0 {
return 0, false
}
return sum / float64(n), true
}