package event import ( "context" "encoding/json" "fmt" "io" "net/http" "strconv" "sync" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" // "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event" ) type service struct { token string store *repository.Store } func New(token string, store *repository.Store) Service { return &service{ token: token, store: store, } } func (s *service) FetchLiveEvents(ctx context.Context) error { sportIDs := []int{1, 13, 78, 18, 91, 16, 17, 14, 12, 3, 2, 4, 83, 15, 92, 94, 8, 19, 36, 66, 9, 75, 90, 95, 110, 107, 151, 162, 148} var wg sync.WaitGroup for _, sportID := range sportIDs { wg.Add(1) go func(sportID int) { defer wg.Done() url := fmt.Sprintf("https://api.b365api.com/v1/bet365/inplay?sport_id=%d&token=%s", sportID, s.token) resp, err := http.Get(url) if err != nil { fmt.Printf(" Failed request for sport_id=%d: %v\n", sportID, err) return } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) var data struct { Success int `json:"success"` Results [][]map[string]interface{} `json:"results"` } if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 { fmt.Printf(" Decode failed for sport_id=%d\nRaw: %s\n", sportID, string(body)) return } for _, group := range data.Results { for _, ev := range group { if getString(ev["type"]) != "EV" { continue } event := domain.Event{ ID: getString(ev["ID"]), SportID: fmt.Sprintf("%d", sportID), MatchName: getString(ev["NA"]), Score: getString(ev["SS"]), MatchMinute: getInt(ev["TM"]), TimerStatus: getString(ev["TT"]), HomeTeamID: getString(ev["HT"]), AwayTeamID: getString(ev["AT"]), HomeKitImage: getString(ev["K1"]), AwayKitImage: getString(ev["K2"]), LeagueName: getString(ev["CT"]), LeagueID: getString(ev["C2"]), LeagueCC: getString(ev["CB"]), StartTime: time.Now().UTC().Format(time.RFC3339), IsLive: true, Status: "live", MatchPeriod: getInt(ev["MD"]), AddedTime: getInt(ev["TA"]), } if err := s.store.SaveEvent(ctx, event); err != nil { fmt.Printf("Could not store live event [id=%s]: %v\n", event.ID, err) } } } }(sportID) } wg.Wait() fmt.Println("All live events fetched and stored.") return nil } func (s *service) FetchUpcomingEvents(ctx context.Context) error { sportIDs := []int{1} for _, sportID := range sportIDs { url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token) resp, err := http.Get(url) if err != nil { continue } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) var data struct { Success int `json:"success"` Results []struct { ID string `json:"id"` SportID string `json:"sport_id"` Time string `json:"time"` League struct { ID string `json:"id"` Name string `json:"name"` } `json:"league"` Home struct { ID string `json:"id"` Name string `json:"name"` } `json:"home"` Away *struct { ID string `json:"id"` Name string `json:"name"` } `json:"away"` } `json:"results"` } if err := json.Unmarshal(body, &data); err != nil || data.Success != 1 { continue } for _, ev := range data.Results { startUnix, _ := strconv.ParseInt(ev.Time, 10, 64) event := domain.UpcomingEvent{ ID: ev.ID, SportID: ev.SportID, MatchName: ev.Home.Name, HomeTeam: ev.Home.Name, AwayTeam: "", // handle nil safely HomeTeamID: ev.Home.ID, AwayTeamID: "", HomeKitImage: "", AwayKitImage: "", LeagueID: ev.League.ID, LeagueName: ev.League.Name, LeagueCC: "", StartTime: time.Unix(startUnix, 0).UTC(), } if ev.Away != nil { event.AwayTeam = ev.Away.Name event.AwayTeamID = ev.Away.ID } _ = s.store.SaveUpcomingEvent(ctx, event) } } return nil } func getString(v interface{}) string { if str, ok := v.(string); ok { return str } return "" } func getInt(v interface{}) int { if f, ok := v.(float64); ok { return int(f) } return 0 } func (s *service) GetAllUpcomingEvents(ctx context.Context) ([]domain.UpcomingEvent, error) { return s.store.GetAllUpcomingEvents(ctx) } func (s *service) GetPaginatedUpcomingEvents(ctx context.Context, limit int32, offset int32, leagueID domain.ValidString, sportID domain.ValidString) ([]domain.UpcomingEvent, int64, error) { return s.store.GetPaginatedUpcomingEvents(ctx, limit, offset, leagueID, sportID) } func (s *service) GetUpcomingEventByID(ctx context.Context, ID string) (domain.UpcomingEvent, error) { return s.store.GetUpcomingEventByID(ctx, ID) }