package odds import ( "context" "encoding/json" "fmt" "io" "net/http" "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/repository" ) type ServiceImpl struct { token string store *repository.Store } func New(token string, store *repository.Store) *ServiceImpl { return &ServiceImpl{token: token, store: store} } func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error { fmt.Println("Starting FetchNonLiveOdds...") sportID := 1 upcomingURL := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s", sportID, s.token) resp, err := http.Get(upcomingURL) if err != nil { fmt.Printf("Failed to fetch upcoming: %v\n", err) return err } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) var upcomingData struct { Success int `json:"success"` Results []struct { ID string `json:"id"` } `json:"results"` } if err := json.Unmarshal(body, &upcomingData); err != nil || upcomingData.Success != 1 { fmt.Printf("Failed to decode upcoming response\nRaw: %s\n", string(body)) return err } for _, ev := range upcomingData.Results { eventID := ev.ID fmt.Printf("Fetching prematch odds for event_id=%s\n", eventID) prematchURL := fmt.Sprintf("https://api.b365api.com/v3/bet365/prematch?token=%s&FI=%s", s.token, eventID) oddsResp, err := http.Get(prematchURL) if err != nil { fmt.Printf(" Odds fetch failed for event_id=%s: %v\n", eventID, err) continue } defer oddsResp.Body.Close() oddsBody, _ := io.ReadAll(oddsResp.Body) fmt.Printf(" Raw odds response for event_id=%s: %.300s...\n", eventID, string(oddsBody)) var oddsData struct { Success int `json:"success"` Results []struct { EventID string `json:"event_id"` FI string `json:"FI"` Main OddsSection `json:"main"` } `json:"results"` } if err := json.Unmarshal(oddsBody, &oddsData); err != nil || oddsData.Success != 1 || len(oddsData.Results) == 0 { fmt.Printf(" Failed odds decode for event_id=%s\nRaw: %s\n", eventID, string(oddsBody)) continue } result := oddsData.Results[0] finalID := result.EventID if finalID == "" { finalID = result.FI } if finalID == "" { fmt.Println(" Skipping event with missing final ID.") continue } fmt.Printf("🗂 Saving prematch odds for event_id=%s\n", finalID) s.storeSection(ctx, finalID, result.FI, "main", result.Main) fmt.Printf(" Finished storing prematch odds for event_id=%s\n", finalID) } fmt.Println(" All prematch odds fetched and stored.") return nil } func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) { fmt.Printf(" Processing section '%s' for event_id=%s\n", sectionName, eventID) if len(section.Sp) == 0 { fmt.Printf(" No odds in section '%s' for event_id=%s\n", sectionName, eventID) return } updatedAtUnix, _ := strconv.ParseInt(section.UpdatedAt, 10, 64) updatedAt := time.Unix(updatedAtUnix, 0) for marketType, market := range section.Sp { fmt.Printf(" Processing market: %s (%s)\n", marketType, market.ID) if len(market.Odds) == 0 { fmt.Printf(" Empty odds for marketType=%s in section=%s\n", marketType, sectionName) continue } marketRecord := domain.Market{ EventID: eventID, FI: fi, MarketCategory: sectionName, MarketType: marketType, MarketName: market.Name, MarketID: market.ID, UpdatedAt: updatedAt, Odds: market.Odds, } fmt.Printf(" Saving market to DB: %s (%s)\n", marketType, market.ID) err := s.store.SaveNonLiveMarket(ctx, marketRecord) if err != nil { fmt.Printf(" Save failed for market %s (%s): %v\n", marketType, eventID, err) } else { fmt.Printf(" Successfully stored market: %s (%s)\n", marketType, eventID) } } } type OddsMarket struct { ID string `json:"id"` Name string `json:"name"` Odds []json.RawMessage `json:"odds"` Header string `json:"header,omitempty"` Handicap string `json:"handicap,omitempty"` } type OddsSection struct { UpdatedAt string `json:"updated_at"` Sp map[string]OddsMarket `json:"sp"` } func getString(v interface{}) string { if str, ok := v.(string); ok { return str } return "" } func (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) { fmt.Printf("Retrieving prematch odds for event_id=%s\n", eventID) odds, err := s.store.GetPrematchOdds(ctx, eventID) if err != nil { fmt.Printf(" Failed to retrieve odds for event_id=%s: %v\n", eventID, err) return nil, err } fmt.Printf(" Retrieved %d odds entries for event_id=%s\n", len(odds), eventID) return odds, nil }