Yimaru-BackEnd/internal/services/odds/service.go
OneTap Technologies a282080133 addign odd data
2025-04-11 15:12:55 +03:00

154 lines
4.4 KiB
Go

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)
}
}
}
// Odds structures
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"`
}
// Utility
func getString(v interface{}) string {
if str, ok := v.(string); ok {
return str
}
return ""
}