1495 lines
45 KiB
Go
1495 lines
45 KiB
Go
package enetpulse
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"io"
|
||
"net/http"
|
||
"strconv"
|
||
"time"
|
||
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||
)
|
||
|
||
type Service struct {
|
||
// username string
|
||
// token string
|
||
cfg config.Config
|
||
store *repository.Store
|
||
// mongoLogger *zap.Logger
|
||
httpClient *http.Client
|
||
}
|
||
|
||
func New(cfg config.Config, store *repository.Store) *Service {
|
||
return &Service{
|
||
cfg: cfg,
|
||
store: store,
|
||
// mongoLogger: mongoLogger,
|
||
httpClient: &http.Client{
|
||
Timeout: 15 * time.Second,
|
||
},
|
||
}
|
||
}
|
||
|
||
func (s *Service) FetchAndStoreSports(ctx context.Context) error {
|
||
// 1️⃣ Compose URL with credentials
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/sport/list/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
// 2️⃣ Create HTTP request with context
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return fmt.Errorf("creating sport request: %w", err)
|
||
}
|
||
|
||
// 3️⃣ Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return fmt.Errorf("requesting sports: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
// 4️⃣ Check response status
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return fmt.Errorf("failed to fetch sports (status %d): %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// 5️⃣ Decode JSON response
|
||
var sportsResp struct {
|
||
Sports map[string]struct {
|
||
ID string `json:"id"`
|
||
N string `json:"n"` // updates count
|
||
Name string `json:"name"`
|
||
UT string `json:"ut"` // timestamp string
|
||
} `json:"sports"`
|
||
}
|
||
if err := json.NewDecoder(resp.Body).Decode(&sportsResp); err != nil {
|
||
return fmt.Errorf("decoding sports response: %w", err)
|
||
}
|
||
|
||
// 6️⃣ Iterate and store each sport
|
||
for _, sport := range sportsResp.Sports {
|
||
// Parse updates count
|
||
updatesCount := 0
|
||
if sport.N != "" {
|
||
if n, err := strconv.Atoi(sport.N); err == nil {
|
||
updatesCount = n
|
||
}
|
||
}
|
||
|
||
// Parse timestamp
|
||
lastUpdatedAt, err := time.Parse(time.RFC3339, sport.UT)
|
||
if err != nil {
|
||
// Fallback to zero time if parsing fails
|
||
lastUpdatedAt = time.Time{}
|
||
}
|
||
|
||
// Build domain object
|
||
createSport := domain.CreateEnetpulseSport{
|
||
SportID: sport.ID,
|
||
Name: sport.Name,
|
||
UpdatesCount: updatesCount,
|
||
LastUpdatedAt: lastUpdatedAt,
|
||
Status: 1, // default active
|
||
}
|
||
|
||
// Insert or update in DB
|
||
if _, err := s.store.CreateEnetpulseSport(ctx, createSport); err != nil {
|
||
// Log error but continue
|
||
// s.logger.Error("failed to store sport", zap.String("sport_id", sport.ID), zap.Error(err))
|
||
continue
|
||
}
|
||
}
|
||
|
||
// s.logger.Info("Successfully fetched and stored sports", zap.Int("count", len(sportsResp.Sports)))
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) GetAllSports(ctx context.Context) ([]domain.EnetpulseSport, error) {
|
||
// 1️⃣ Fetch all sports from the store (database)
|
||
sports, err := s.store.GetAllEnetpulseSports(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch sports from DB: %w", err)
|
||
}
|
||
|
||
// 2️⃣ Optionally, you can log the count or perform other transformations
|
||
// s.logger.Info("Fetched sports from DB", zap.Int("count", len(sports)))
|
||
|
||
return sports, nil
|
||
}
|
||
|
||
func (s *Service) FetchAndStoreTournamentTemplates(ctx context.Context) error {
|
||
// 1️⃣ Fetch all sports from the database
|
||
sports, err := s.store.GetAllEnetpulseSports(ctx)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to fetch sports from DB: %w", err)
|
||
}
|
||
|
||
// Template struct
|
||
type TournamentTemplate struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
SportFK string `json:"sportFK"`
|
||
Gender string `json:"gender"`
|
||
N string `json:"n"`
|
||
UT string `json:"ut"`
|
||
}
|
||
|
||
for _, sport := range sports {
|
||
// 2️⃣ Compose URL for each sport using its Enetpulse sportFK
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament_template/list/?sportFK=%s&username=%s&token=%s",
|
||
sport.SportID, // must be Enetpulse sportFK
|
||
s.cfg.EnetPulseConfig.UserName,
|
||
s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
fmt.Println("Fetching tournament templates:", url)
|
||
|
||
// 3️⃣ Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return fmt.Errorf("creating tournament template request for sport %s: %w", sport.SportID, err)
|
||
}
|
||
|
||
// 4️⃣ Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return fmt.Errorf("requesting tournament templates for sport %s: %w", sport.SportID, err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return fmt.Errorf("failed to fetch tournament templates for sport %s (status %d): %s",
|
||
sport.SportID, resp.StatusCode, string(body))
|
||
}
|
||
|
||
// 5️⃣ Decode JSON response flexibly
|
||
var raw struct {
|
||
TournamentTemplates json.RawMessage `json:"tournament_templates"`
|
||
}
|
||
bodyBytes, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return fmt.Errorf("reading tournament templates response for sport %s: %w", sport.SportID, err)
|
||
}
|
||
if err := json.Unmarshal(bodyBytes, &raw); err != nil {
|
||
return fmt.Errorf("unmarshalling raw tournament templates for sport %s: %w", sport.SportID, err)
|
||
}
|
||
|
||
// 6️⃣ Parse depending on object or array
|
||
templates := map[string]TournamentTemplate{}
|
||
if len(raw.TournamentTemplates) > 0 && raw.TournamentTemplates[0] == '{' {
|
||
// Object (normal case)
|
||
if err := json.Unmarshal(raw.TournamentTemplates, &templates); err != nil {
|
||
return fmt.Errorf("decoding tournament templates (object) for sport %s: %w", sport.SportID, err)
|
||
}
|
||
} else {
|
||
// Array or empty → skip safely
|
||
fmt.Printf("No tournament templates found for sport %s\n", sport.SportID)
|
||
continue
|
||
}
|
||
|
||
// 7️⃣ Iterate and store each tournament template
|
||
for _, tmpl := range templates {
|
||
updatesCount := 0
|
||
if tmpl.N != "" {
|
||
if n, err := strconv.Atoi(tmpl.N); err == nil {
|
||
updatesCount = n
|
||
}
|
||
}
|
||
|
||
lastUpdatedAt, err := time.Parse(time.RFC3339, tmpl.UT)
|
||
if err != nil {
|
||
lastUpdatedAt = time.Time{}
|
||
}
|
||
|
||
// Convert sport.SportID from string to int64
|
||
sportFK, err := strconv.ParseInt(sport.SportID, 10, 64)
|
||
if err != nil {
|
||
fmt.Printf("failed to convert sport.SportID '%s' to int64: %v\n", sport.SportID, err)
|
||
continue
|
||
}
|
||
|
||
createTemplate := domain.CreateEnetpulseTournamentTemplate{
|
||
TemplateID: tmpl.ID,
|
||
Name: tmpl.Name,
|
||
SportFK: sportFK, // use DB sport ID internally
|
||
Gender: tmpl.Gender,
|
||
UpdatesCount: updatesCount,
|
||
LastUpdatedAt: lastUpdatedAt,
|
||
Status: 1, // default active
|
||
}
|
||
|
||
if _, err := s.store.CreateEnetpulseTournamentTemplate(ctx, createTemplate); err != nil {
|
||
fmt.Printf("failed to store tournament template %s: %v\n", tmpl.ID, err)
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
fmt.Println("✅ Successfully fetched and stored all tournament templates")
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) GetAllTournamentTemplates(ctx context.Context) ([]domain.EnetpulseTournamentTemplate, error) {
|
||
// 1️⃣ Fetch all tournament templates from the store (database)
|
||
templates, err := s.store.GetAllEnetpulseTournamentTemplates(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch tournament templates from DB: %w", err)
|
||
}
|
||
|
||
// 2️⃣ Optionally, you can log the count or perform other transformations
|
||
// s.logger.Info("Fetched tournament templates from DB", zap.Int("count", len(templates)))
|
||
|
||
return templates, nil
|
||
}
|
||
|
||
func (s *Service) FetchAndStoreTournaments(ctx context.Context) error {
|
||
// 1️⃣ Fetch all tournament templates from the database
|
||
templates, err := s.store.GetAllEnetpulseTournamentTemplates(ctx)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to fetch tournament templates from DB: %w", err)
|
||
}
|
||
|
||
for _, tmpl := range templates {
|
||
// 2️⃣ Compose URL for each tournament template
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament/list/?tournament_templateFK=%s&username=%s&token=%s",
|
||
tmpl.TemplateID,
|
||
s.cfg.EnetPulseConfig.UserName,
|
||
s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
// 3️⃣ Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return fmt.Errorf("creating tournament request for template %s: %w", tmpl.TemplateID, err)
|
||
}
|
||
|
||
// 4️⃣ Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return fmt.Errorf("requesting tournaments for template %s: %w", tmpl.TemplateID, err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return fmt.Errorf("failed to fetch tournaments for template %s (status %d): %s",
|
||
tmpl.TemplateID, resp.StatusCode, string(body))
|
||
}
|
||
|
||
// 5️⃣ Decode JSON response
|
||
var tournamentsResp struct {
|
||
Tournaments map[string]struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
TournamentTemplateFK string `json:"tournament_templateFK"`
|
||
N string `json:"n"` // updates count
|
||
UT string `json:"ut"` // timestamp
|
||
} `json:"tournaments"`
|
||
}
|
||
if err := json.NewDecoder(resp.Body).Decode(&tournamentsResp); err != nil {
|
||
return fmt.Errorf("decoding tournaments for template %s: %w", tmpl.TemplateID, err)
|
||
}
|
||
|
||
// 6️⃣ Iterate and store each tournament
|
||
for _, t := range tournamentsResp.Tournaments {
|
||
updatesCount := 0
|
||
if t.N != "" {
|
||
if n, err := strconv.Atoi(t.N); err == nil {
|
||
updatesCount = n
|
||
}
|
||
}
|
||
|
||
lastUpdatedAt, err := time.Parse(time.RFC3339, t.UT)
|
||
if err != nil {
|
||
lastUpdatedAt = time.Time{}
|
||
}
|
||
|
||
createTournament := domain.CreateEnetpulseTournament{
|
||
TournamentID: t.ID,
|
||
Name: t.Name,
|
||
TournamentTemplateFK: tmpl.TemplateID, // DB ID of template
|
||
UpdatesCount: updatesCount,
|
||
LastUpdatedAt: lastUpdatedAt,
|
||
Status: 1, // default active
|
||
}
|
||
|
||
// Insert into DB
|
||
if _, err := s.store.CreateEnetpulseTournament(ctx, createTournament); err != nil {
|
||
// Log error but continue
|
||
// s.logger.Error("failed to store tournament", zap.String("tournament_id", t.ID), zap.Error(err))
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
// s.logger.Info("Successfully fetched and stored all tournaments")
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) GetAllTournaments(ctx context.Context) ([]domain.EnetpulseTournament, error) {
|
||
// 1️⃣ Fetch all tournaments from the store (database)
|
||
tournaments, err := s.store.GetAllEnetpulseTournaments(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch tournaments from DB: %w", err)
|
||
}
|
||
|
||
// 2️⃣ Optionally log count or do transformations
|
||
// s.logger.Info("Fetched tournaments from DB", zap.Int("count", len(tournaments)))
|
||
|
||
return tournaments, nil
|
||
}
|
||
|
||
func (s *Service) FetchAndStoreTournamentStages(ctx context.Context) error {
|
||
// 1️⃣ Get all tournaments from DB
|
||
tournaments, err := s.store.GetAllEnetpulseTournaments(ctx)
|
||
if err != nil {
|
||
return fmt.Errorf("failed to fetch tournaments from DB: %w", err)
|
||
}
|
||
|
||
// 2️⃣ Loop through each tournament
|
||
for _, t := range tournaments {
|
||
// Compose URL for each tournament
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament_stage/list/?language_typeFK=3&tz=Europe/Sofia&tournamentFK=%s&username=%s&token=%s",
|
||
t.TournamentID,
|
||
s.cfg.EnetPulseConfig.UserName,
|
||
s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
// 3️⃣ Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
// log and skip
|
||
// s.logger.Error("creating tournament stages request", zap.String("tournament_id", t.TournamentID), zap.Error(err))
|
||
continue
|
||
}
|
||
|
||
// 4️⃣ Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
// s.logger.Error("requesting tournament stages", zap.String("tournament_id", t.TournamentID), zap.Error(err))
|
||
continue
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
// s.logger.Error("unexpected status code fetching stages", zap.String("tournament_id", t.TournamentID), zap.Int("status", resp.StatusCode))
|
||
_ = body
|
||
continue
|
||
}
|
||
|
||
// 5️⃣ Decode JSON response (based on EnetPulse response format)
|
||
var stagesResp struct {
|
||
Stages map[string]struct {
|
||
ID string `json:"id"`
|
||
Name string `json:"name"`
|
||
TournamentFK string `json:"tournamentFK"`
|
||
N string `json:"n"` // updates count
|
||
UT string `json:"ut"` // timestamp
|
||
} `json:"tournament_stages"`
|
||
}
|
||
if err := json.NewDecoder(resp.Body).Decode(&stagesResp); err != nil {
|
||
// s.logger.Error("decoding tournament stages", zap.String("tournament_id", t.TournamentID), zap.Error(err))
|
||
continue
|
||
}
|
||
|
||
// 6️⃣ Iterate and store each stage
|
||
for _, st := range stagesResp.Stages {
|
||
updatesCount := 0
|
||
if st.N != "" {
|
||
if n, err := strconv.Atoi(st.N); err == nil {
|
||
updatesCount = n
|
||
}
|
||
}
|
||
|
||
lastUpdatedAt, err := time.Parse(time.RFC3339, st.UT)
|
||
if err != nil {
|
||
lastUpdatedAt = time.Time{}
|
||
}
|
||
|
||
createStage := domain.CreateEnetpulseTournamentStage{
|
||
StageID: st.ID,
|
||
Name: st.Name,
|
||
TournamentFK: t.TournamentID, // DB ID of the tournament
|
||
UpdatesCount: updatesCount,
|
||
LastUpdatedAt: lastUpdatedAt,
|
||
Status: 1,
|
||
}
|
||
|
||
// Insert into DB
|
||
if _, err := s.store.CreateEnetpulseTournamentStage(ctx, createStage); err != nil {
|
||
// s.logger.Error("failed to store tournament stage", zap.String("stage_id", st.ID), zap.Error(err))
|
||
continue
|
||
}
|
||
}
|
||
}
|
||
|
||
// s.logger.Info("Successfully fetched and stored all tournament stages for all tournaments")
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) GetAllTournamentStages(ctx context.Context) ([]domain.EnetpulseTournamentStage, error) {
|
||
// 1️⃣ Fetch all tournament stages from the store (database)
|
||
stages, err := s.store.GetAllEnetpulseTournamentStages(ctx)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to fetch tournament stages from DB: %w", err)
|
||
}
|
||
|
||
// 2️⃣ Optionally log count or perform transformations
|
||
// s.logger.Info("Fetched tournament stages from DB", zap.Int("count", len(stages)))
|
||
|
||
return stages, nil
|
||
}
|
||
|
||
func (s *Service) FetchTournamentTemplates(ctx context.Context) (*domain.TournamentTemplatesResponse, error) {
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournamenttemplate/list/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating tournament template request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting tournament templates: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("failed to fetch tournament templates: %s, body: %s", resp.Status, string(body))
|
||
}
|
||
|
||
var templatesResp domain.TournamentTemplatesResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&templatesResp); err != nil {
|
||
return nil, fmt.Errorf("decoding tournament templates response: %w", err)
|
||
}
|
||
|
||
// Optionally save to DB or cache
|
||
return &templatesResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchTournamentTemplateParticipants(ctx context.Context, templateID string, opts domain.ParticipantsOptions) (*domain.TournamentTemplateParticipantsResponse, error) {
|
||
// Build URL with optional parameters
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournamenttemplate/participants/?username=%s&token=%s&id=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token, templateID,
|
||
)
|
||
|
||
// Append optional params if set
|
||
if opts.IncludeProperties {
|
||
url += "&includeProperties=yes"
|
||
}
|
||
if opts.IncludeParticipantProperties {
|
||
url += "&includeParticipantProperties=yes"
|
||
}
|
||
if opts.IncludeParticipantSports {
|
||
url += "&includeParticipantSports=yes"
|
||
}
|
||
if opts.IncludeCountries {
|
||
url += "&includeCountries=yes"
|
||
}
|
||
if opts.IncludeCountryCodes {
|
||
url += "&includeCountryCodes=yes"
|
||
}
|
||
if opts.ParticipantType != "" {
|
||
url += "&participantType=" + opts.ParticipantType
|
||
}
|
||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating tournament participants request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting tournament participants: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("failed to fetch tournament participants: %s, body: %s", resp.Status, string(body))
|
||
}
|
||
|
||
var participantsResp domain.TournamentTemplateParticipantsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&participantsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding tournament participants response: %w", err)
|
||
}
|
||
|
||
// Optionally save to DB or cache
|
||
return &participantsResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchTournaments(ctx context.Context, templateID string) error {
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament/list/?tournament_templateFK=%s&username=%s&token=%s",
|
||
templateID, s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return fmt.Errorf("creating tournament request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return fmt.Errorf("requesting tournaments: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return fmt.Errorf("failed to fetch tournaments (status %d): %s",
|
||
resp.StatusCode, string(body))
|
||
}
|
||
|
||
var tournamentsResp domain.TournamentsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&tournamentsResp); err != nil {
|
||
return fmt.Errorf("decoding tournaments response: %w", err)
|
||
}
|
||
|
||
// Example: save tournaments to store or log them
|
||
for _, tournament := range tournamentsResp.Tournaments {
|
||
fmt.Printf("Tournament ID=%s Name=%s TemplateFK=%s UpdatedAt=%s\n",
|
||
tournament.ID, tournament.Name, tournament.TournamentTemplateFK, tournament.UT)
|
||
// e.g. s.store.SaveTournament(ctx, tournament)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) FetchTournamentParticipants(ctx context.Context, tournamentID string) error {
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament_stage/participants/?id=%s&participantType=team&username=%s&token=%s",
|
||
tournamentID, s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return fmt.Errorf("creating tournament participants request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return fmt.Errorf("requesting tournament participants: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return fmt.Errorf("failed to fetch tournament participants (status %d): %s",
|
||
resp.StatusCode, string(body))
|
||
}
|
||
|
||
var participantsResp domain.TournamentParticipantsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&participantsResp); err != nil {
|
||
return fmt.Errorf("decoding tournament participants response: %w", err)
|
||
}
|
||
|
||
// Example: loop participants
|
||
for tid, t := range participantsResp.Tournaments {
|
||
fmt.Printf("Tournament ID=%s Name=%s has %d participants\n",
|
||
tid, t.Name, len(t.Participants))
|
||
// You can loop deeper into t.Participants and store
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) FetchTournamentStages(ctx context.Context, tournamentFK string) (*domain.TournamentStagesResponse, error) {
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament_stage/list/?language_typeFK=3&tz=Europe/Sofia&tournamentFK=%s&username=%s&token=%s",
|
||
tournamentFK, s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating tournament stages request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting tournament stages: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
var stagesResp domain.TournamentStagesResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&stagesResp); err != nil {
|
||
return nil, fmt.Errorf("decoding tournament stages response: %w", err)
|
||
}
|
||
|
||
// optionally save to DB or cache here
|
||
return &stagesResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchTournamentStageParticipants(
|
||
ctx context.Context,
|
||
stageID string,
|
||
includeProps, includeParticipantProps, includeCountries, includeCountryCodes bool,
|
||
) (*domain.TournamentStageParticipantsResponse, error) {
|
||
url := fmt.Sprintf(
|
||
"http://eapi.enetpulse.com/tournament_stage/participants/?id=%s&includeProperties=%s&includeParticipantProperties=%s&includeCountries=%s&includeCountryCodes=%s&username=%s&token=%s",
|
||
stageID,
|
||
boolToYesNo(includeProps),
|
||
boolToYesNo(includeParticipantProps),
|
||
boolToYesNo(includeCountries),
|
||
boolToYesNo(includeCountryCodes),
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token,
|
||
)
|
||
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating participants request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting participants: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
var participantsResp domain.TournamentStageParticipantsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&participantsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding participants response: %w", err)
|
||
}
|
||
|
||
// optionally save to DB or cache here
|
||
return &participantsResp, nil
|
||
}
|
||
|
||
// helper function to convert bool to yes/no
|
||
func boolToYesNo(v bool) string {
|
||
if v {
|
||
return "yes"
|
||
}
|
||
return "no"
|
||
}
|
||
|
||
func (s *Service) FetchDailyEvents(ctx context.Context, req domain.DailyEventsRequest) (*domain.DailyEventsResponse, error) {
|
||
baseURL := "http://eapi.enetpulse.com/event/daily/"
|
||
query := fmt.Sprintf("?username=%s&token=%s&language_typeFK=3", s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Required at least one of sportFK / tournament_templateFK / tournament_stageFK
|
||
if req.SportFK != 0 {
|
||
query += fmt.Sprintf("&sportFK=%d", req.SportFK)
|
||
}
|
||
if req.TournamentTemplateFK != 0 {
|
||
query += fmt.Sprintf("&tournament_templateFK=%d", req.TournamentTemplateFK)
|
||
}
|
||
if req.TournamentStageFK != 0 {
|
||
query += fmt.Sprintf("&tournament_stageFK=%d", req.TournamentStageFK)
|
||
}
|
||
|
||
// Optionals
|
||
if req.Date != "" {
|
||
query += fmt.Sprintf("&date=%s", req.Date)
|
||
}
|
||
if req.Live != "" {
|
||
query += fmt.Sprintf("&live=%s", req.Live)
|
||
}
|
||
if req.IncludeVenue != "" {
|
||
query += fmt.Sprintf("&includeVenue=%s", req.IncludeVenue)
|
||
}
|
||
if req.StatusType != "" {
|
||
query += fmt.Sprintf("&status_type=%s", req.StatusType)
|
||
}
|
||
if req.IncludeEventProperties != "" {
|
||
query += fmt.Sprintf("&includeEventProperties=%s", req.IncludeEventProperties)
|
||
}
|
||
if req.IncludeCountryCodes != "" {
|
||
query += fmt.Sprintf("&includeCountryCodes=%s", req.IncludeCountryCodes)
|
||
}
|
||
if req.IncludeFirstLastName != "" {
|
||
query += fmt.Sprintf("&includeFirstLastName=%s", req.IncludeFirstLastName)
|
||
}
|
||
if req.IncludeDeleted != "" {
|
||
query += fmt.Sprintf("&includeDeleted=%s", req.IncludeDeleted)
|
||
}
|
||
|
||
fullURL := baseURL + query
|
||
|
||
httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, fullURL, nil)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(httpReq)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("failed to fetch daily events: status %d body: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
var dailyResp domain.DailyEventsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&dailyResp); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return &dailyResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchFixtures(ctx context.Context, params domain.FixturesRequest) (*domain.FixturesResponse, error) {
|
||
// Build base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/event/fixtures/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Required filter: one of sportFK | tournament_templateFK | tournament_stageFK
|
||
if params.SportFK != 0 {
|
||
url += fmt.Sprintf("&sportFK=%d", params.SportFK)
|
||
}
|
||
if params.TournamentTemplateFK != 0 {
|
||
url += fmt.Sprintf("&tournament_templateFK=%d", params.TournamentTemplateFK)
|
||
}
|
||
if params.TournamentStageFK != 0 {
|
||
url += fmt.Sprintf("&tournament_stageFK=%d", params.TournamentStageFK)
|
||
}
|
||
|
||
// Optional filters
|
||
if params.LanguageTypeFK != 0 {
|
||
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
|
||
} else {
|
||
url += "&language_typeFK=3" // default to English
|
||
}
|
||
if params.Date != "" {
|
||
url += fmt.Sprintf("&date=%s", params.Date)
|
||
}
|
||
if params.Live != "" {
|
||
url += fmt.Sprintf("&live=%s", params.Live)
|
||
}
|
||
if params.IncludeVenue {
|
||
url += "&includeVenue=yes"
|
||
}
|
||
if !params.IncludeEventProperties {
|
||
url += "&includeEventProperties=no"
|
||
}
|
||
if params.IncludeCountryCodes {
|
||
url += "&includeCountryCodes=yes"
|
||
}
|
||
if params.IncludeFirstLastName {
|
||
url += "&includeFirstLastName=yes"
|
||
}
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating fixtures request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting fixtures: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var fixturesResp domain.FixturesResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&fixturesResp); err != nil {
|
||
return nil, fmt.Errorf("decoding fixtures response: %w", err)
|
||
}
|
||
|
||
return &fixturesResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchResults(ctx context.Context, params domain.ResultsRequest) (*domain.ResultsResponse, error) {
|
||
// Build base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/event/results/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Required filters (at least one of them)
|
||
if params.SportFK != 0 {
|
||
url += fmt.Sprintf("&sportFK=%d", params.SportFK)
|
||
}
|
||
if params.TournamentTemplateFK != 0 {
|
||
url += fmt.Sprintf("&tournament_templateFK=%d", params.TournamentTemplateFK)
|
||
}
|
||
if params.TournamentStageFK != 0 {
|
||
url += fmt.Sprintf("&tournament_stageFK=%d", params.TournamentStageFK)
|
||
}
|
||
|
||
// Optional filters
|
||
if params.LanguageTypeFK != 0 {
|
||
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
|
||
} else {
|
||
url += "&language_typeFK=3" // default English
|
||
}
|
||
if params.Date != "" {
|
||
url += fmt.Sprintf("&date=%s", params.Date)
|
||
}
|
||
if params.Live != "" {
|
||
url += fmt.Sprintf("&live=%s", params.Live)
|
||
}
|
||
if params.IncludeVenue {
|
||
url += "&includeVenue=yes"
|
||
}
|
||
if !params.IncludeEventProperties {
|
||
url += "&includeEventProperties=no"
|
||
}
|
||
if params.IncludeCountryCodes {
|
||
url += "&includeCountryCodes=yes"
|
||
}
|
||
if params.IncludeFirstLastName {
|
||
url += "&includeFirstLastName=yes"
|
||
}
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating results request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting results: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var resultsResp domain.ResultsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&resultsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding results response: %w", err)
|
||
}
|
||
|
||
return &resultsResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchEventDetails(ctx context.Context, params domain.EventDetailsRequest) (*domain.EventDetailsResponse, error) {
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/event/details/?username=%s&token=%s&id=%d",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token, params.ID)
|
||
|
||
// Optional flags
|
||
if params.IncludeLineups {
|
||
url += "&includeLineups=yes"
|
||
}
|
||
if params.IncludeIncidents {
|
||
url += "&includeIncidents=yes"
|
||
}
|
||
if !params.IncludeExtendedResults {
|
||
url += "&includeExtendedResults=no"
|
||
}
|
||
if params.IncludeProperties {
|
||
url += "&includeProperties=yes"
|
||
}
|
||
if params.IncludeLivestats {
|
||
url += "&includeLivestats=yes"
|
||
}
|
||
if params.IncludeVenue {
|
||
url += "&includeVenue=yes"
|
||
}
|
||
if params.IncludeCountryCodes {
|
||
url += "&includeCountryCodes=yes"
|
||
}
|
||
if params.IncludeFirstLastName {
|
||
url += "&includeFirstLastName=yes"
|
||
}
|
||
if params.IncludeDeleted {
|
||
url += "&includeDeleted=yes"
|
||
}
|
||
if params.IncludeReference {
|
||
url += "&includeReference=yes"
|
||
}
|
||
if params.IncludeObjectParticipants {
|
||
url += "&includeObjectParticipants=yes"
|
||
}
|
||
if params.IncludeEventIncidentRelation {
|
||
url += "&includeEventIncidentRelation=yes"
|
||
}
|
||
if params.IncludeTeamProperties {
|
||
url += "&includeTeamProperties=yes"
|
||
}
|
||
if params.IncludeObjectRound {
|
||
url += "&includeObjectRound=yes"
|
||
}
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating event details request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting event details: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var detailsResp domain.EventDetailsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&detailsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding event details response: %w", err)
|
||
}
|
||
|
||
return &detailsResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchEventList(ctx context.Context, params domain.EventListRequest) (*domain.EventListResponse, error) {
|
||
// You must provide either TournamentFK or TournamentStageFK
|
||
if params.TournamentFK == 0 && params.TournamentStageFK == 0 {
|
||
return nil, fmt.Errorf("either TournamentFK or TournamentStageFK is required")
|
||
}
|
||
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/event/list/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Mandatory one of
|
||
if params.TournamentFK != 0 {
|
||
url += fmt.Sprintf("&tournamentFK=%d", params.TournamentFK)
|
||
}
|
||
if params.TournamentStageFK != 0 {
|
||
url += fmt.Sprintf("&tournament_stageFK=%d", params.TournamentStageFK)
|
||
}
|
||
|
||
// Optional parameters
|
||
if !params.IncludeEventProperties {
|
||
url += "&includeEventProperties=no"
|
||
}
|
||
if params.StatusType != "" {
|
||
url += "&status_type=" + params.StatusType
|
||
}
|
||
if params.IncludeVenue {
|
||
url += "&includeVenue=yes"
|
||
}
|
||
if params.IncludeDeleted {
|
||
url += "&includeDeleted=yes"
|
||
}
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating event list request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting event list: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var eventListResp domain.EventListResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&eventListResp); err != nil {
|
||
return nil, fmt.Errorf("decoding event list response: %w", err)
|
||
}
|
||
|
||
return &eventListResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchParticipantFixtures(ctx context.Context, params domain.ParticipantFixturesRequest) (*domain.ParticipantFixturesResponse, error) {
|
||
// You must provide ParticipantFK
|
||
if params.ParticipantFK == 0 {
|
||
return nil, fmt.Errorf("ParticipantFK is required")
|
||
}
|
||
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/event/participant_fixtures/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Mandatory param
|
||
url += fmt.Sprintf("&participantFK=%d", params.ParticipantFK)
|
||
|
||
// Optionals
|
||
if params.SportFK != 0 {
|
||
url += fmt.Sprintf("&sportFK=%d", params.SportFK)
|
||
}
|
||
if params.TournamentFK != 0 {
|
||
url += fmt.Sprintf("&tournamentFK=%d", params.TournamentFK)
|
||
}
|
||
if params.TournamentTemplateFK != 0 {
|
||
url += fmt.Sprintf("&tournament_templateFK=%d", params.TournamentTemplateFK)
|
||
}
|
||
if params.TournamentStageFK != 0 {
|
||
url += fmt.Sprintf("&tournament_stageFK=%d", params.TournamentStageFK)
|
||
}
|
||
if params.Date != "" {
|
||
url += "&date=" + params.Date
|
||
}
|
||
if params.Live != "" {
|
||
url += "&live=" + params.Live
|
||
}
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
|
||
if params.IncludeVenue {
|
||
url += "&includeVenue=yes"
|
||
}
|
||
if params.IncludeCountryCodes {
|
||
url += "&includeCountryCodes=yes"
|
||
}
|
||
if params.IncludeFirstLastName {
|
||
url += "&includeFirstLastName=yes"
|
||
}
|
||
if !params.IncludeEventProperties {
|
||
// default yes → only append when false
|
||
url += "&includeEventProperties=no"
|
||
}
|
||
if params.LanguageTypeFK != 0 {
|
||
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
|
||
}
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating participant fixtures request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting participant fixtures: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var fixturesResp domain.ParticipantFixturesResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&fixturesResp); err != nil {
|
||
return nil, fmt.Errorf("decoding participant fixtures response: %w", err)
|
||
}
|
||
|
||
return &fixturesResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchParticipantResults(ctx context.Context, params domain.ParticipantResultsRequest) (*domain.ParticipantResultsResponse, error) {
|
||
// Required param
|
||
if params.ParticipantFK == 0 {
|
||
return nil, fmt.Errorf("participantFK is required")
|
||
}
|
||
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/event/participant_results/?username=%s&token=%s&participantFK=%d",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token, params.ParticipantFK)
|
||
|
||
// Optional parameters
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
if params.IncludeDeleted {
|
||
url += "&includeDeleted=yes"
|
||
}
|
||
if params.IncludeVenue {
|
||
url += "&includeVenue=yes"
|
||
}
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating participant_results request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting participant_results: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var prResp domain.ParticipantResultsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&prResp); err != nil {
|
||
return nil, fmt.Errorf("decoding participant_results response: %w", err)
|
||
}
|
||
|
||
return &prResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchTeamLogo(ctx context.Context, teamFK int64) (*domain.TeamLogoResponse, error) {
|
||
if teamFK == 0 {
|
||
return nil, fmt.Errorf("teamFK is required")
|
||
}
|
||
|
||
// Build URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/image/team_logo/?teamFK=%d&username=%s&token=%s",
|
||
teamFK, s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating team logo request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting team logo: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Read image bytes
|
||
data, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("reading team logo body: %w", err)
|
||
}
|
||
|
||
// Build response
|
||
return &domain.TeamLogoResponse{
|
||
ContentType: resp.Header.Get("Content-Type"),
|
||
Data: data,
|
||
URL: url, // optional: you can also return the URL for reference
|
||
}, nil
|
||
}
|
||
|
||
func (s *Service) FetchTeamShirts(ctx context.Context, teamFK int64) (*domain.TeamShirtsResponse, error) {
|
||
if teamFK == 0 {
|
||
return nil, fmt.Errorf("teamFK is required")
|
||
}
|
||
|
||
// Build URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/image/team_shirt/?teamFK=%d&username=%s&token=%s",
|
||
teamFK, s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Make request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating team shirts request: %w", err)
|
||
}
|
||
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting team shirts: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Read response bytes — because shirts may come back as JSON list of URLs *or* image bytes
|
||
data, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("reading team shirts body: %w", err)
|
||
}
|
||
|
||
// Build response — since Enetpulse typically returns a list of image URLs,
|
||
// we’ll return raw bytes if only one image, or JSON if multiple images.
|
||
return &domain.TeamShirtsResponse{
|
||
ContentType: resp.Header.Get("Content-Type"),
|
||
RawData: data,
|
||
URL: url,
|
||
}, nil
|
||
}
|
||
|
||
func (s *Service) FetchCountryFlag(ctx context.Context, countryFK int64) (*domain.ImageResponse, error) {
|
||
if countryFK == 0 {
|
||
return nil, fmt.Errorf("countryFK is required")
|
||
}
|
||
|
||
// Build URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/image/country_flag/?countryFK=%d&username=%s&token=%s",
|
||
countryFK, s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating country flag request: %w", err)
|
||
}
|
||
|
||
// Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting country flag: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Read image bytes
|
||
data, err := io.ReadAll(resp.Body)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("reading country flag body: %w", err)
|
||
}
|
||
|
||
// Return response
|
||
return &domain.ImageResponse{
|
||
ContentType: resp.Header.Get("Content-Type"),
|
||
RawData: data,
|
||
URL: url,
|
||
}, nil
|
||
}
|
||
|
||
func (s *Service) FetchPreMatchOdds(ctx context.Context, params domain.PreMatchOddsRequest) (*domain.PreMatchOddsResponse, error) {
|
||
// Mandatory parameter check
|
||
if params.ObjectFK == 0 {
|
||
return nil, fmt.Errorf("objectFK (event ID) is required")
|
||
}
|
||
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/preodds/event/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Mandatory parameters
|
||
url += fmt.Sprintf("&objectFK=%d", params.ObjectFK)
|
||
if len(params.OddsProviderFK) > 0 {
|
||
url += "&odds_providerFK=" + joinIntSlice(params.OddsProviderFK)
|
||
}
|
||
if params.OutcomeTypeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_typeFK=%d", params.OutcomeTypeFK)
|
||
}
|
||
if params.OutcomeScopeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_scopeFK=%d", params.OutcomeScopeFK)
|
||
}
|
||
if params.OutcomeSubtypeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_subtypeFK=%d", params.OutcomeSubtypeFK)
|
||
}
|
||
|
||
// Optional parameters
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
if params.LanguageTypeFK != 0 {
|
||
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
|
||
}
|
||
|
||
// Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating pre-match odds request: %w", err)
|
||
}
|
||
|
||
// Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting pre-match odds: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var oddsResp domain.PreMatchOddsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&oddsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding pre-match odds response: %w", err)
|
||
}
|
||
|
||
return &oddsResp, nil
|
||
}
|
||
|
||
// Helper function to join int slice with comma
|
||
func joinIntSlice(slice []int64) string {
|
||
result := ""
|
||
for i, v := range slice {
|
||
if i > 0 {
|
||
result += ","
|
||
}
|
||
result += fmt.Sprintf("%d", v)
|
||
}
|
||
return result
|
||
}
|
||
|
||
func (s *Service) FetchTournamentStageOdds(ctx context.Context, params domain.TournamentStageOddsRequest) (*domain.TournamentStageOddsResponse, error) {
|
||
// Mandatory parameter check
|
||
if params.ObjectFK == 0 {
|
||
return nil, fmt.Errorf("objectFK (tournament stage ID) is required")
|
||
}
|
||
if params.OutcomeTypeFK == 0 {
|
||
return nil, fmt.Errorf("outcomeTypeFK is required")
|
||
}
|
||
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/preodds/tournament_stage/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Mandatory parameters
|
||
url += fmt.Sprintf("&objectFK=%d", params.ObjectFK)
|
||
url += fmt.Sprintf("&outcome_typeFK=%d", params.OutcomeTypeFK)
|
||
if params.OddsProviderFK != 0 {
|
||
url += fmt.Sprintf("&odds_providerFK=%d", params.OddsProviderFK)
|
||
}
|
||
if params.OutcomeScopeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_scopeFK=%d", params.OutcomeScopeFK)
|
||
}
|
||
if params.OutcomeSubtypeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_subtypeFK=%d", params.OutcomeSubtypeFK)
|
||
}
|
||
|
||
// Optional parameters
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
if params.LanguageTypeFK != 0 {
|
||
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
|
||
}
|
||
|
||
// Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating tournament stage odds request: %w", err)
|
||
}
|
||
|
||
// Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting tournament stage odds: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var oddsResp domain.TournamentStageOddsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&oddsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding tournament stage odds response: %w", err)
|
||
}
|
||
|
||
return &oddsResp, nil
|
||
}
|
||
|
||
func (s *Service) FetchTournamentOdds(ctx context.Context, params domain.TournamentOddsRequest) (*domain.TournamentOddsResponse, error) {
|
||
// Mandatory parameter check
|
||
if params.ObjectFK == 0 {
|
||
return nil, fmt.Errorf("objectFK (tournament ID) is required")
|
||
}
|
||
if params.OutcomeTypeFK == 0 {
|
||
return nil, fmt.Errorf("outcomeTypeFK is required")
|
||
}
|
||
|
||
// Base URL
|
||
url := fmt.Sprintf("http://eapi.enetpulse.com/preodds/tournament/?username=%s&token=%s",
|
||
s.cfg.EnetPulseConfig.UserName, s.cfg.EnetPulseConfig.Token)
|
||
|
||
// Mandatory parameters
|
||
url += fmt.Sprintf("&objectFK=%d", params.ObjectFK)
|
||
url += fmt.Sprintf("&outcome_typeFK=%d", params.OutcomeTypeFK)
|
||
if params.OddsProviderFK != 0 {
|
||
url += fmt.Sprintf("&odds_providerFK=%d", params.OddsProviderFK)
|
||
}
|
||
if params.OutcomeScopeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_scopeFK=%d", params.OutcomeScopeFK)
|
||
}
|
||
if params.OutcomeSubtypeFK != 0 {
|
||
url += fmt.Sprintf("&outcome_subtypeFK=%d", params.OutcomeSubtypeFK)
|
||
}
|
||
|
||
// Optional parameters
|
||
if params.Limit > 0 {
|
||
url += fmt.Sprintf("&limit=%d", params.Limit)
|
||
}
|
||
if params.Offset > 0 {
|
||
url += fmt.Sprintf("&offset=%d", params.Offset)
|
||
}
|
||
if params.LanguageTypeFK != 0 {
|
||
url += fmt.Sprintf("&language_typeFK=%d", params.LanguageTypeFK)
|
||
}
|
||
|
||
// Create HTTP request
|
||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("creating tournament odds request: %w", err)
|
||
}
|
||
|
||
// Execute request
|
||
resp, err := s.httpClient.Do(req)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("requesting tournament odds: %w", err)
|
||
}
|
||
defer resp.Body.Close()
|
||
|
||
if resp.StatusCode != http.StatusOK {
|
||
body, _ := io.ReadAll(resp.Body)
|
||
return nil, fmt.Errorf("unexpected status %d: %s", resp.StatusCode, string(body))
|
||
}
|
||
|
||
// Decode response
|
||
var oddsResp domain.TournamentOddsResponse
|
||
if err := json.NewDecoder(resp.Body).Decode(&oddsResp); err != nil {
|
||
return nil, fmt.Errorf("decoding tournament odds response: %w", err)
|
||
}
|
||
|
||
return &oddsResp, nil
|
||
}
|