package odds import ( "context" "encoding/json" "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 { 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, } for _, sportID := range sportIDs { upcomingURL := "https://api.b365api.com/v1/bet365/upcoming?sport_id=" + strconv.Itoa(sportID) + "&token=" + s.token resp, err := http.Get(upcomingURL) if err != nil { continue } 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 { continue } for _, ev := range upcomingData.Results { eventID := ev.ID prematchURL := "https://api.b365api.com/v3/bet365/prematch?token=" + s.token + "&FI=" + eventID oddsResp, err := http.Get(prematchURL) if err != nil { continue } defer oddsResp.Body.Close() oddsBody, _ := io.ReadAll(oddsResp.Body) 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 { continue } result := oddsData.Results[0] finalID := result.EventID if finalID == "" { finalID = result.FI } if finalID == "" { continue } s.storeSection(ctx, finalID, result.FI, "main", result.Main) } } return nil } func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section OddsSection) { if len(section.Sp) == 0 { return } updatedAtUnix, _ := strconv.ParseInt(section.UpdatedAt, 10, 64) updatedAt := time.Unix(updatedAtUnix, 0) for marketType, market := range section.Sp { if len(market.Odds) == 0 { continue } marketRecord := domain.Market{ EventID: eventID, FI: fi, MarketCategory: sectionName, MarketType: marketType, MarketName: market.Name, MarketID: market.ID, UpdatedAt: updatedAt, Odds: market.Odds, } _ = s.store.SaveNonLiveMarket(ctx, marketRecord) } } 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 (s *ServiceImpl) GetPrematchOdds(ctx context.Context, eventID string) ([]domain.Odd, error) { return s.store.GetPrematchOdds(ctx, eventID) } func (s *ServiceImpl) GetALLPrematchOdds(ctx context.Context) ([]domain.Odd, error) { return s.store.GetALLPrematchOdds(ctx) } func (s *ServiceImpl) GetRawOddsByID(ctx context.Context, rawOddsID string) ([]domain.RawOddsByID, error) { rawOdds, err := s.store.GetRawOddsByID(ctx, rawOddsID) if err != nil { return nil, err } return []domain.RawOddsByID{rawOdds}, nil }