package result

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"log/slog"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
	"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
)

type Service struct {
	repo      *repository.Store
	config    *config.Config
	logger    *slog.Logger
	client    *http.Client
	betSvc    bet.Service
	oddSvc    odds.ServiceImpl
	eventSvc  event.Service
	leagueSvc league.Service
}

func NewService(repo *repository.Store, cfg *config.Config, logger *slog.Logger, betSvc bet.Service, oddSvc odds.ServiceImpl, eventSvc event.Service, leagueSvc league.Service) *Service {
	return &Service{
		repo:      repo,
		config:    cfg,
		logger:    logger,
		client:    &http.Client{Timeout: 10 * time.Second},
		betSvc:    betSvc,
		oddSvc:    oddSvc,
		eventSvc:  eventSvc,
		leagueSvc: leagueSvc,
	}
}

var (
	ErrEventIsNotActive = fmt.Errorf("event has been cancelled or postponed")
)

func (s *Service) FetchAndProcessResults(ctx context.Context) error {
	// TODO: Optimize this because there could be many bet outcomes for the same odd
	// Take market id and match result as param and update all the bet outcomes at the same time
	events, err := s.repo.GetExpiredUpcomingEvents(ctx, domain.EventFilter{})
	if err != nil {
		s.logger.Error("Failed to fetch events")
		return err
	}
	fmt.Printf("⚠️  Expired Events: %d \n", len(events))
	removed := 0
	errs := make([]error, 0, len(events))
	for i, event := range events {

		eventID, err := strconv.ParseInt(event.ID, 10, 64)
		if err != nil {
			s.logger.Error("Failed to parse event id")
			errs = append(errs, fmt.Errorf("failed to parse event id %s: %w", event.ID, err))
			continue
		}
		outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
		if err != nil {
			s.logger.Error("Failed to get pending bet outcomes", "error", err)
			errs = append(errs, fmt.Errorf("failed to get pending bet outcomes for event %d: %w", eventID, err))
			continue
		}

		if len(outcomes) == 0 {
			fmt.Printf("🕛 No bets have been placed on event %v (%d/%d) \n", event.ID, i+1, len(events))
		} else {
			fmt.Printf("✅ %d bets have been placed on event %v (%d/%d) \n", len(outcomes), event.ID, i+1, len(events))
		}

		isDeleted := true
		result, err := s.fetchResult(ctx, eventID)
		if err != nil {
			if err == ErrEventIsNotActive {
				s.logger.Warn("Event is not active", "event_id", eventID, "error", err)
				continue
			}
			s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
			continue
		}
		var commonResp domain.CommonResultResponse
		if err := json.Unmarshal(result.Results[0], &commonResp); err != nil {
			s.logger.Error("Failed to unmarshal common result", "event_id", eventID, "error", err)
			continue
		}

		sportID, err := strconv.ParseInt(commonResp.SportID, 10, 64)
		if err != nil {
			s.logger.Error("Failed to parse sport id", "event_id", eventID, "error", err)
			continue
		}
		timeStatusParsed, err := strconv.ParseInt(strings.TrimSpace(commonResp.TimeStatus), 10, 64)
		if err != nil {
			s.logger.Error("Failed to parse time status", "time_status", commonResp.TimeStatus, "error", err)
			continue
		}

		// TODO: Figure out what to do with the events that have been cancelled or postponed, etc...
		if timeStatusParsed != int64(domain.TIME_STATUS_ENDED) {
			s.logger.Warn("Event is not ended yet", "event_id", eventID, "time_status", commonResp.TimeStatus)
			fmt.Printf("⚠️  Event %v is not ended yet (%d/%d) \n", event.ID, i+1, len(events))
			isDeleted = false
			continue
		}

		for j, outcome := range outcomes {
			fmt.Printf("⚙️  Processing 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
				outcome.MarketName,
				event.HomeTeam+" "+event.AwayTeam, event.ID,
				j+1, len(outcomes))

			if outcome.Expires.After(time.Now()) {
				isDeleted = false
				s.logger.Warn("Outcome is not expired yet", "event_id", event.ID, "outcome_id", outcome.ID)
				continue
			}

			parseResult, err := s.parseResult(ctx, result.Results[0], outcome, sportID)
			if err != nil {
				isDeleted = false
				s.logger.Error("Failed to parse result", "event_id", outcome.EventID, "outcome_id", outcome.ID, "error", err)
				errs = append(errs, fmt.Errorf("failed to parse result for event %d: %w", outcome.EventID, err))
				continue
			}
			outcome, err = s.betSvc.UpdateBetOutcomeStatus(ctx, outcome.ID, parseResult.Status)
			if err != nil {
				isDeleted = false
				s.logger.Error("Failed to update bet outcome status", "bet_outcome_id", outcome.ID, "error", err)
				continue
			}
			if outcome.Status == domain.OUTCOME_STATUS_ERROR || outcome.Status == domain.OUTCOME_STATUS_PENDING {
				fmt.Printf("❌ Error while updating 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
					outcome.MarketName,
					event.HomeTeam+" "+event.AwayTeam, event.ID,
					j+1, len(outcomes))

				s.logger.Error("Outcome is pending or error", "event_id", outcome.EventID, "outcome_id", outcome.ID)
				isDeleted = false
				continue
			}

			fmt.Printf("✅  Successfully updated 🎲 outcomes '%v' for event %v(%v) (%d/%d) \n",
				outcome.MarketName,
				event.HomeTeam+" "+event.AwayTeam, event.ID,
				j+1, len(outcomes))

			status, err := s.betSvc.CheckBetOutcomeForBet(ctx, outcome.BetID)
			if err != nil {
				if err != bet.ErrOutcomesNotCompleted {
					s.logger.Error("Failed to check bet outcome for bet", "event_id", outcome.EventID, "error", err)
				}
				isDeleted = false
				continue
			}
			fmt.Printf("🧾 Updating bet %v - event %v (%d/%d) to %v\n", outcome.BetID, event.ID, j+1, len(outcomes), status.String())
			err = s.betSvc.UpdateStatus(ctx, outcome.BetID, status)
			if err != nil {
				s.logger.Error("Failed to update bet status", "event id", outcome.EventID, "error", err)
				isDeleted = false
				continue
			}
			fmt.Printf("✅  Successfully updated 🎫 Bet %v - event %v(%v) (%d/%d) \n",
				outcome.BetID,
				event.HomeTeam+" "+event.AwayTeam, event.ID,
				j+1, len(outcomes))

		}
		if isDeleted {
			removed += 1
			fmt.Printf("⚠️  Removing Event %v \n", event.ID)
			err = s.repo.DeleteEvent(ctx, event.ID)
			if err != nil {
				s.logger.Error("Failed to remove event", "event_id", event.ID, "error", err)
				return err
			}
			err = s.repo.DeleteOddsForEvent(ctx, event.ID)
			if err != nil {
				s.logger.Error("Failed to remove odds for event", "event_id", event.ID, "error", err)
				return err
			}
		}

	}
	fmt.Printf("🗑️  Removed Events: %d \n", removed)
	if len(errs) > 0 {
		s.logger.Error("Errors occurred while processing results", "errors", errs)
		for _, err := range errs {
			fmt.Println("Error:", err)
		}
		return fmt.Errorf("errors occurred while processing results: %v", errs)
	}
	s.logger.Info("Successfully processed results", "removed_events", removed, "total_events", len(events))
	return nil
}

func (s *Service) CheckAndUpdateExpiredEvents(ctx context.Context) (int64, error) {
	events, err := s.repo.GetExpiredUpcomingEvents(ctx, domain.EventFilter{})
	if err != nil {
		s.logger.Error("Failed to fetch events")
		return 0, err
	}
	fmt.Printf("⚠️  Expired Events: %d \n", len(events))
	updated := 0
	for i, event := range events {
		fmt.Printf("⚙️  Processing event %v (%d/%d) \n", event.ID, i+1, len(events))
		eventID, err := strconv.ParseInt(event.ID, 10, 64)
		if err != nil {
			s.logger.Error("Failed to parse event id")
			continue
		}

		if event.Status == domain.STATUS_REMOVED {
			s.logger.Info("Skipping updating removed event")
			continue
		}
		result, err := s.fetchResult(ctx, eventID)
		if err != nil {
			s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
			continue
		}
		if result.Success != 1 || len(result.Results) == 0 {
			s.logger.Error("Invalid API response", "event_id", eventID)
			fmt.Printf("⚠️  Invalid API response for event %v \n", result)
			continue
		}

		var commonResp domain.CommonResultResponse
		if err := json.Unmarshal(result.Results[0], &commonResp); err != nil {
			s.logger.Error("Failed to unmarshal common result", "event_id", eventID, "error", err)
			continue
		}

		var eventStatus domain.EventStatus
		// TODO Change event status to int64 enum
		timeStatus, err := strconv.ParseInt(strings.TrimSpace(commonResp.TimeStatus), 10, 64)
		switch timeStatus {
		case int64(domain.TIME_STATUS_NOT_STARTED):
			eventStatus = domain.STATUS_PENDING
		case int64(domain.TIME_STATUS_IN_PLAY):
			eventStatus = domain.STATUS_IN_PLAY
		case int64(domain.TIME_STATUS_TO_BE_FIXED):
			eventStatus = domain.STATUS_TO_BE_FIXED
		case int64(domain.TIME_STATUS_ENDED):
			eventStatus = domain.STATUS_ENDED
		case int64(domain.TIME_STATUS_POSTPONED):
			eventStatus = domain.STATUS_POSTPONED
		case int64(domain.TIME_STATUS_CANCELLED):
			eventStatus = domain.STATUS_CANCELLED
		case int64(domain.TIME_STATUS_WALKOVER):
			eventStatus = domain.STATUS_WALKOVER
		case int64(domain.TIME_STATUS_INTERRUPTED):
			eventStatus = domain.STATUS_INTERRUPTED
		case int64(domain.TIME_STATUS_ABANDONED):
			eventStatus = domain.STATUS_ABANDONED
		case int64(domain.TIME_STATUS_RETIRED):
			eventStatus = domain.STATUS_RETIRED
		case int64(domain.TIME_STATUS_SUSPENDED):
			eventStatus = domain.STATUS_SUSPENDED
		case int64(domain.TIME_STATUS_DECIDED_BY_FA):
			eventStatus = domain.STATUS_DECIDED_BY_FA
		case int64(domain.TIME_STATUS_REMOVED):
			eventStatus = domain.STATUS_REMOVED
		default:
			s.logger.Error("Invalid time status", "time_status", commonResp.TimeStatus, "event_id", eventID)
		}

		err = s.eventSvc.UpdateFinalScore(ctx, strconv.FormatInt(eventID, 10), commonResp.SS, eventStatus)
		if err != nil {
			s.logger.Error("Failed to update final score", "event_id", eventID, "error", err)
			continue
		}
		updated++
		fmt.Printf("✅  Successfully updated event %v to %v (%d/%d) \n", event.ID, eventStatus, i+1, len(events))

		// Update the league because the league country code is only found on the result response
		leagueID, err := strconv.ParseInt(commonResp.League.ID, 10, 64)
		if err != nil {
			log.Printf("❌ Invalid league id,  leagueID %v", commonResp.League.ID)
			continue
		}

		err = s.leagueSvc.UpdateLeague(ctx, domain.UpdateLeague{
			ID: int64(event.LeagueID),
			CountryCode: domain.ValidString{
				Value: commonResp.League.CC,
				Valid: true,
			},
			Bet365ID: domain.ValidInt32{
				Value: int32(leagueID),
				Valid: true,
			},
		})

		if err != nil {
			log.Printf("❌ Error Updating League %v", commonResp.League.Name)
			log.Printf("err:%v", err)
			continue
		}
		fmt.Printf("✅ Updated League %v with country code %v \n", leagueID, commonResp.League.CC)

	}

	if updated == 0 {
		s.logger.Info("No events were updated")
		return 0, nil
	}

	s.logger.Info("Successfully updated live events", "updated_events", updated, "total_events", len(events))
	return int64(updated), nil

}

func (s *Service) GetResultsForEvent(ctx context.Context, eventID string) (json.RawMessage, []domain.BetOutcome, error) {
	id, err := strconv.ParseInt(eventID, 10, 64)
	if err != nil {
		s.logger.Error("Failed to parse event id")
		return json.RawMessage{}, nil, err
	}

	result, err := s.fetchResult(ctx, id)
	if err != nil {
		s.logger.Error("Failed to fetch result", "event_id", id, "error", err)
	}
	if result.Success != 1 || len(result.Results) == 0 {
		fmt.Printf("⚠️  Invalid API response for event %v \n", result)
		s.logger.Error("Invalid API response", "event_id", id)
		return json.RawMessage{}, nil, fmt.Errorf("invalid API response for event %d", id)
	}

	var commonResp domain.CommonResultResponse
	if err := json.Unmarshal(result.Results[0], &commonResp); err != nil {
		s.logger.Error("Failed to unmarshal common result", "event_id", eventID, "error", err)
		return json.RawMessage{}, nil, err
	}

	sportID, err := strconv.ParseInt(commonResp.SportID, 10, 32)
	if err != nil {
		s.logger.Error("Failed to parse sport id", "event_id", eventID, "error", err)
		return json.RawMessage{}, nil, fmt.Errorf("failed to parse sport id: %w", err)
	}

	expireUnix, err := strconv.ParseInt(commonResp.Time, 10, 64)
	if err != nil {
		s.logger.Error("Failed to parse expire time", "event_id", eventID, "error", err)
		return json.RawMessage{}, nil, fmt.Errorf("Failed to parse expire time for event %s: %w", eventID, err)
	}

	expires := time.Unix(expireUnix, 0)

	odds, err := s.oddSvc.FetchNonLiveOddsByEventID(ctx, eventID)
	if err != nil {
		s.logger.Error("Failed to fetch non-live odds by event ID", "event_id", eventID, "error", err)
		return json.RawMessage{}, nil, fmt.Errorf("failed to fetch non-live odds for event %s: %w", eventID, err)
	}

	parsedOddSections, err := s.oddSvc.ParseOddSections(ctx, odds.Results[0], int32(sportID))
	if err != nil {
		s.logger.Error("Failed to parse odd section", "error", err)
		return json.RawMessage{}, nil, fmt.Errorf("failed to parse odd section for event %v: %w", eventID, err)
	}

	outcomes := make([]domain.BetOutcome, 0)
	for _, section := range parsedOddSections.Sections {
		// TODO: Remove repeat code here, same as in odds service
		for _, market := range section.Sp {
			var marketIDstr string
			err := json.Unmarshal(market.ID, &marketIDstr)
			var marketIDint int64
			if err != nil {
				// check if its int
				err := json.Unmarshal(market.ID, &marketIDint)
				if err != nil {
					s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
					continue
				}
			} else {
				marketIDint, err = strconv.ParseInt(marketIDstr, 10, 64)
				if err != nil {
					s.logger.Error("Invalid market id", "marketID", marketIDstr, "marketName", market.Name)
					continue
				}
			}

			isSupported, ok := domain.SupportedMarkets[marketIDint]

			if !ok || !isSupported {
				// s.logger.Info("Unsupported market_id", "marketID", marketIDint, "marketName", market.Name)
				continue
			}
			for _, oddRes := range market.Odds {
				var odd domain.RawOdd
				if err := json.Unmarshal(oddRes, &odd); err != nil {
					s.logger.Error("Failed to unmarshal odd", "error", err)
					continue
				}

				oddID, err := strconv.ParseInt(odd.ID, 10, 64)

				if err != nil {
					s.logger.Error("Failed to parse odd id", "odd_id", odd.ID, "error", err)
					continue
				}

				oddValue, err := strconv.ParseFloat(odd.Odds, 64)
				if err != nil {
					s.logger.Error("Failed to parse odd value", "odd_value", odd.Odds, "error", err)
					continue
				}

				outcome := domain.BetOutcome{
					EventID:      id,
					MarketID:     marketIDint,
					OddID:        oddID,
					MarketName:   market.Name,
					OddHeader:    odd.Header,
					OddHandicap:  odd.Handicap,
					OddName:      odd.Name,
					Odd:          float32(oddValue),
					SportID:      sportID,
					HomeTeamName: commonResp.Home.Name,
					AwayTeamName: commonResp.Away.Name,
					Status:       domain.OUTCOME_STATUS_PENDING,
					Expires:      expires,
					BetID:        0, // This won't be set
				}
				outcomes = append(outcomes, outcome)
			}

		}

	}

	if len(outcomes) == 0 {
		s.logger.Warn("No outcomes found for event", "event_id", eventID)
		return json.RawMessage{}, nil, fmt.Errorf("no outcomes found for event %s", eventID)
	}
	s.logger.Info("Successfully fetched outcomes for event", "event_id", eventID, "outcomes_count", len(outcomes))

	// Get results for outcome
	for i, outcome := range outcomes {
		// Parse the result based on sport type
		parsedResult, err := s.parseResult(ctx, result.Results[0], outcome, sportID)
		if err != nil {
			s.logger.Error("Failed to parse result for outcome", "event_id", outcome.EventID, "error", err)
			return json.RawMessage{}, nil, fmt.Errorf("failed to parse result for outcome %d: %w", i, err)
		}
		outcomes[i].Status = parsedResult.Status
	}

	return result.Results[0], outcomes, err
}

func (s *Service) fetchResult(ctx context.Context, eventID int64) (domain.BaseResultResponse, error) {
	url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%d", s.config.Bet365Token, eventID)
	// url := fmt.Sprintf("https://api.b365api.com/v1/event/view?token=%s&event_id=%d", s.config.Bet365Token, eventID)

	req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
	if err != nil {
		s.logger.Error("Failed to create request", "event_id", eventID, "error", err)
		return domain.BaseResultResponse{}, err
	}

	resp, err := s.client.Do(req)
	if err != nil {
		s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err)
		return domain.BaseResultResponse{}, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		s.logger.Error("Unexpected status code", "event_id", eventID, "status_code", resp.StatusCode)
		return domain.BaseResultResponse{}, fmt.Errorf("unexpected status code: %d", resp.StatusCode)
	}

	var resultResp domain.BaseResultResponse
	if err := json.NewDecoder(resp.Body).Decode(&resultResp); err != nil {
		s.logger.Error("Failed to decode result", "event_id", eventID, "error", err)
		return domain.BaseResultResponse{}, err
	}

	if resultResp.Success != 1 || len(resultResp.Results) == 0 {
		s.logger.Error("Invalid API response", "event_id", eventID)
		fmt.Printf("⚠️  Invalid API response for event %v \n", resultResp)
		return domain.BaseResultResponse{}, fmt.Errorf("invalid API response")
	}

	return resultResp, nil
}

func (s *Service) parseResult(ctx context.Context, resultResp json.RawMessage, outcome domain.BetOutcome, sportID int64) (domain.CreateResult, error) {

	var result domain.CreateResult
	var err error
	switch sportID {
	case domain.FOOTBALL:
		result, err = s.parseFootball(resultResp, outcome)
		if err != nil {
			s.logger.Error("Failed to parse football", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.BASKETBALL:
		result, err = s.parseBasketball(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse basketball", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.ICE_HOCKEY:
		result, err = s.parseIceHockey(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse ice hockey", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.CRICKET:
		result, err = s.parseCricket(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse cricket", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.VOLLEYBALL:
		result, err = s.parseVolleyball(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse volleyball", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.DARTS:
		result, err = s.parseDarts(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse darts", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.FUTSAL:
		result, err = s.parseFutsal(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse futsal", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.AMERICAN_FOOTBALL:
		result, err = s.parseNFL(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse american football", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.RUGBY_UNION:
		result, err = s.parseRugbyUnion(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse rugby_union", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.RUGBY_LEAGUE:
		result, err = s.parseRugbyLeague(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse rugby_league", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	case domain.BASEBALL:
		result, err = s.parseBaseball(resultResp, outcome.EventID, outcome.OddID, outcome.MarketID, outcome)
		if err != nil {
			s.logger.Error("Failed to parse baseball", "event id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
			return domain.CreateResult{}, err
		}
	default:
		s.logger.Error("Unsupported sport", "sport", sportID)
		return domain.CreateResult{}, fmt.Errorf("unsupported sport: %v", sportID)
	}

	return result, nil
}

func (s *Service) parseFootball(resultRes json.RawMessage, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var fbResp domain.FootballResultResponse
	if err := json.Unmarshal(resultRes, &fbResp); err != nil {
		s.logger.Error("Failed to unmarshal football result", "event_id", outcome.EventID, "error", err)
		return domain.CreateResult{}, err
	}
	result := fbResp

	finalScore := parseSS(result.SS)
	firstHalfScore := parseScore(result.Scores.FirstHalf.Home, result.Scores.FirstHalf.Away)
	secondHalfScore := parseScore(result.Scores.SecondHalf.Home, result.Scores.SecondHalf.Away)

	corners := parseStats(result.Stats.Corners)
	halfTimeCorners := parseStats(result.Stats.HalfTimeCorners)
	status, err := s.evaluateFootballOutcome(outcome, finalScore, firstHalfScore, secondHalfScore, corners, halfTimeCorners, result.Events)
	if err != nil {
		s.logger.Error("Failed to evaluate football outcome", "event_id", outcome.EventID, "market_id", outcome.MarketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      outcome.EventID,
		OddID:        outcome.OddID,
		MarketID:     outcome.MarketID,
		Status:       status,
		Score:        result.SS,
	}, nil

}

func (s *Service) parseBasketball(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var basketBallRes domain.BasketballResultResponse

	if err := json.Unmarshal(response, &basketBallRes); err != nil {
		s.logger.Error("Failed to unmarshal basketball result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}

	status, err := s.evaluateBasketballOutcome(outcome, basketBallRes)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
		Score:        basketBallRes.SS,
	}, nil

}

func (s *Service) parseIceHockey(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var iceHockeyRes domain.IceHockeyResultResponse
	if err := json.Unmarshal(response, &iceHockeyRes); err != nil {
		s.logger.Error("Failed to unmarshal ice hockey result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}

	status, err := s.evaluateIceHockeyOutcome(outcome, iceHockeyRes)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
		Score:        iceHockeyRes.SS,
	}, nil

}

func (s *Service) parseCricket(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var cricketRes domain.CricketResultResponse

	if err := json.Unmarshal(response, &cricketRes); err != nil {
		s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}
	if cricketRes.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}

	status, err := s.evaluateCricketOutcome(outcome, cricketRes)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
	}, nil
}

func (s *Service) parseVolleyball(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var volleyballRes domain.VolleyballResultResponse

	if err := json.Unmarshal(response, &volleyballRes); err != nil {
		s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}
	if volleyballRes.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}

	status, err := s.evaluateVolleyballOutcome(outcome, volleyballRes)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
	}, nil

}

func (s *Service) parseDarts(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var dartsRes domain.DartsResultResponse

	if err := json.Unmarshal(response, &dartsRes); err != nil {
		s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}

	if dartsRes.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}

	// result for dart is limited
	// only ss is given, format with 2-4
	status, err := s.evaluateDartsOutcome(outcome, dartsRes)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
	}, nil

}

func (s *Service) parseFutsal(response json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var futsalRes domain.FutsalResultResponse

	if err := json.Unmarshal(response, &futsalRes); err != nil {
		s.logger.Error("Failed to unmarshal football result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}

	if futsalRes.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}

	status, err := s.evaluateFutsalOutcome(outcome, futsalRes)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: 0,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
	}, nil

}

func (s *Service) parseNFL(resultRes json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var nflResp domain.NFLResultResponse
	if err := json.Unmarshal(resultRes, &nflResp); err != nil {
		s.logger.Error("Failed to unmarshal NFL result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}

	if nflResp.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}

	status, err := s.evaluateNFLOutcome(outcome, nflResp)

	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}

	return domain.CreateResult{
		BetOutcomeID: outcome.ID,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
		Score:        nflResp.SS,
	}, nil
}

func (s *Service) parseRugbyUnion(resultRes json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var rugbyResp domain.RugbyResultResponse
	if err := json.Unmarshal(resultRes, &rugbyResp); err != nil {
		s.logger.Error("Failed to unmarshal Rugby Union result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}
	if rugbyResp.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}
	status, err := s.evaluateRugbyOutcome(outcome, rugbyResp)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}
	return domain.CreateResult{
		BetOutcomeID: outcome.ID,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
		Score:        rugbyResp.SS,
	}, nil
}

func (s *Service) parseRugbyLeague(resultRes json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var rugbyResp domain.RugbyResultResponse
	if err := json.Unmarshal(resultRes, &rugbyResp); err != nil {
		s.logger.Error("Failed to unmarshal Rugby League result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}
	if rugbyResp.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}
	status, err := s.evaluateRugbyOutcome(outcome, rugbyResp)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}
	return domain.CreateResult{
		BetOutcomeID: outcome.ID,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
		Score:        rugbyResp.SS,
	}, nil
}

func (s *Service) parseBaseball(resultRes json.RawMessage, eventID, oddID, marketID int64, outcome domain.BetOutcome) (domain.CreateResult, error) {
	var baseballResp domain.BaseballResultResponse
	if err := json.Unmarshal(resultRes, &baseballResp); err != nil {
		s.logger.Error("Failed to unmarshal Baseball result", "event_id", eventID, "error", err)
		return domain.CreateResult{}, err
	}
	if baseballResp.TimeStatus != "3" {
		s.logger.Warn("Match not yet completed", "event_id", eventID)
		return domain.CreateResult{}, fmt.Errorf("match not yet completed")
	}
	status, err := s.evaluateBaseballOutcome(outcome, baseballResp)
	if err != nil {
		s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err)
		return domain.CreateResult{}, err
	}
	return domain.CreateResult{
		BetOutcomeID: outcome.ID,
		EventID:      eventID,
		OddID:        oddID,
		MarketID:     marketID,
		Status:       status,
		Score:        baseballResp.SS,
	}, nil
}

func parseScore(home string, away string) struct{ Home, Away int } {
	homeVal, _ := strconv.Atoi(strings.TrimSpace(home))
	awaVal, _ := strconv.Atoi(strings.TrimSpace(away))
	return struct{ Home, Away int }{Home: homeVal, Away: awaVal}
}

func parseSS(scoreStr string) struct{ Home, Away int } {
	parts := strings.Split(scoreStr, "-")
	if len(parts) != 2 {
		return struct{ Home, Away int }{0, 0}
	}
	home, _ := strconv.Atoi(strings.TrimSpace(parts[0]))
	away, _ := strconv.Atoi(strings.TrimSpace(parts[1]))
	return struct{ Home, Away int }{Home: home, Away: away}
}

func parseStats(stats []string) struct{ Home, Away int } {
	if len(stats) != 2 {
		return struct{ Home, Away int }{0, 0}
	}
	home, _ := strconv.Atoi(stats[0])
	away, _ := strconv.Atoi(stats[1])
	return struct{ Home, Away int }{Home: home, Away: away}
}

// evaluateOutcome determines the outcome status based on market type and odd
func (s *Service) evaluateFootballOutcome(outcome domain.BetOutcome, finalScore,
	firstHalfScore struct{ Home, Away int }, secondHalfScore struct{ Home, Away int },
	corners struct{ Home, Away int }, halfTimeCorners struct{ Home, Away int },
	events []map[string]string) (domain.OutcomeStatus, error) {

	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	switch outcome.MarketID {
	case int64(domain.FOOTBALL_FULL_TIME_RESULT):
		return evaluateFullTimeResult(outcome, finalScore)
	case int64(domain.FOOTBALL_GOALS_OVER_UNDER):
		return evaluateGoalsOverUnder(outcome, finalScore)
	case int64(domain.FOOTBALL_CORRECT_SCORE):
		return evaluateCorrectScore(outcome, finalScore)
	case int64(domain.FOOTBALL_HALF_TIME_RESULT):
		return evaluateHalfTimeResult(outcome, firstHalfScore)
	case int64(domain.FOOTBALL_ASIAN_HANDICAP):
		return evaluateAsianHandicap(outcome, finalScore)
	case int64(domain.FOOTBALL_GOAL_LINE):
		return evaluateGoalLine(outcome, finalScore)
	case int64(domain.FOOTBALL_FIRST_HALF_ASIAN_HANDICAP):
		return evaluateAsianHandicap(outcome, firstHalfScore)
	case int64(domain.FOOTBALL_FIRST_HALF_GOAL_LINE):
		return evaluateGoalLine(outcome, firstHalfScore)
	case int64(domain.FOOTBALL_FIRST_TEAM_TO_SCORE):
		return evaluateFirstTeamToScore(outcome, events)
	case int64(domain.FOOTBALL_GOALS_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, finalScore)
	case int64(domain.FOOTBALL_DOUBLE_CHANCE):
		return evaluateDoubleChance(outcome, finalScore)
	case int64(domain.FOOTBALL_DRAW_NO_BET):
		return evaluateDrawNoBet(outcome, finalScore)
	case int64(domain.FOOTBALL_CORNERS):
		return evaluateCorners(outcome, corners)
	case int64(domain.FOOTBALL_CORNERS_TWO_WAY):
		return evaluateCorners(outcome, corners)
	case int64(domain.FOOTBALL_FIRST_HALF_CORNERS):
		return evaluateCorners(outcome, halfTimeCorners)
	case int64(domain.FOOTBALL_ASIAN_TOTAL_CORNERS):
		return evaluateCorners(outcome, corners)
	case int64(domain.FOOTBALL_FIRST_HALF_ASIAN_CORNERS):
		return evaluateCorners(outcome, halfTimeCorners)
	case int64(domain.FOOTBALL_FIRST_HALF_GOALS_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, firstHalfScore)
	case int64(domain.FOOTBALL_SECOND_HALF_GOALS_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, secondHalfScore)

	default:
		s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("market type not implemented: %s", outcome.MarketName)
	}
}

func (s *Service) evaluateBasketballOutcome(outcome domain.BetOutcome, res domain.BasketballResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	finalScore := parseSS(res.SS)

	firstHalfScore := parseScore(res.Scores.FirstHalf.Home, res.Scores.FirstHalf.Away)
	secondHalfScore := struct{ Home, Away int }{Home: finalScore.Home - firstHalfScore.Home, Away: finalScore.Away - firstHalfScore.Away}

	firstQuarter := parseScore(res.Scores.FirstQuarter.Home, res.Scores.FirstQuarter.Away)
	secondQuarter := parseScore(res.Scores.SecondQuarter.Home, res.Scores.SecondQuarter.Away)
	thirdQuarter := parseScore(res.Scores.ThirdQuarter.Home, res.Scores.ThirdQuarter.Away)
	fourthQuarter := parseScore(res.Scores.FourthQuarter.Home, res.Scores.FourthQuarter.Away)

	switch outcome.MarketID {
	case int64(domain.BASKETBALL_GAME_LINES):
		return evaluateGameLines(outcome, finalScore)
	case int64(domain.BASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTS):
		return evaluateResultAndBTTSX(outcome, finalScore)
	case int64(domain.BASKETBALL_DOUBLE_RESULT):
		return evaluateDoubleResult(outcome, firstHalfScore, secondHalfScore)
	case int64(domain.BASKETBALL_MATCH_RESULT_AND_TOTAL):
		return evaluateResultAndTotal(outcome, finalScore)
	case int64(domain.BASKETBALL_MATCH_HANDICAP_AND_TOTAL):
		return evaluateHandicapAndTotal(outcome, finalScore)
	case int64(domain.BASKETBALL_GAME_TOTAL_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, finalScore)
	case int64(domain.BASKETBALL_TEAM_TOTALS):
		return evaluateTeamTotal(outcome, finalScore)
	case int64(domain.BASKETBALL_TEAM_TOTAL_ODD_EVEN):
		return evaluateTeamOddEven(outcome, finalScore)

	case int64(domain.BASKETBALL_FIRST_HALF):
		return evaluateGameLines(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_FIRST_HALF_TEAM_TOTALS):
		return evaluateTeamTotal(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_FIRST_HALF_HANDICAP_AND_TOTAL):
		return evaluateHandicapAndTotal(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_FIRST_HALF_BOTH_TEAMS_TO_SCORE_X_POINTS):
		return evaluateBTTSX(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_FIRST_HALF_DOUBLE_CHANCE):
		return evaluateDoubleChance(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_FIRST_HALF_TOTAL_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_FIRST_HALF_MONEY_LINE_3_WAY):
		return evaluateMoneyLine3Way(outcome, firstHalfScore)
	case int64(domain.BASKETBALL_HIGHEST_SCORING_HALF):
		return evaluateHighestScoringHalf(outcome, firstHalfScore, secondHalfScore)

	case int64(domain.BASKETBALL_FIRST_QUARTER):
		return evaluateGameLines(outcome, firstQuarter)
	case int64(domain.BASKETBALL_FIRST_QUARTER_TEAM_TOTALS):
		return evaluateTeamTotal(outcome, firstQuarter)
	case int64(domain.BASKETBALL_FIRST_QUARTER_TOTAL_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, firstQuarter)
	case int64(domain.BASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTAL):
		return evaluateHandicapAndTotal(outcome, firstQuarter)
	case int64(domain.BASKETBALL_FIRST_QUARTER_DOUBLE_CHANCE):
		return evaluateDoubleChance(outcome, firstQuarter)
	case int64(domain.BASKETBALL_HIGHEST_SCORING_QUARTER):
		return evaluateHighestScoringQuarter(outcome, firstQuarter, secondQuarter, thirdQuarter, fourthQuarter)
	case int64(domain.BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL):
		return evaluateResultAndTotal(outcome, firstQuarter)

	case int64(domain.BASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTER):
		return evaluateTeamWithHighestScoringQuarter(outcome, firstQuarter, secondQuarter, thirdQuarter, fourthQuarter)

	default:
		s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("market type not implemented: %s", outcome.MarketName)
	}
}

func (s *Service) evaluateIceHockeyOutcome(outcome domain.BetOutcome, res domain.IceHockeyResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}
	finalScore := parseSS(res.SS)
	firstPeriod := parseScore(res.Scores.FirstPeriod.Home, res.Scores.FirstPeriod.Away)
	secondPeriod := parseScore(res.Scores.SecondPeriod.Home, res.Scores.SecondPeriod.Away)
	thirdPeriod := parseScore(res.Scores.ThirdPeriod.Home, res.Scores.ThirdPeriod.Away)

	regulation := []struct{ Home, Away int }{
		firstPeriod,
		secondPeriod,
		thirdPeriod,
	}
	switch outcome.MarketID {
	case int64(domain.ICE_HOCKEY_GAME_LINES):
		return evaluateGameLines(outcome, finalScore)
	case int64(domain.ICE_HOCKEY_THREE_WAY):
		return evaluateGameLines(outcome, finalScore)
	case int64(domain.ICE_HOCKEY_FIRST_PERIOD):
		return evaluateGameLines(outcome, firstPeriod)
	case int64(domain.ICE_HOCKEY_DRAW_NO_BET):
		return evaluateDrawNoBet(outcome, finalScore)
	case int64(domain.ICE_HOCKEY_DOUBLE_CHANCE):
		return evaluateDoubleChance(outcome, finalScore)
	case int64(domain.ICE_HOCKEY_WINNING_MARGIN):
		return evaluateWinningMargin(outcome, finalScore)
	case int64(domain.ICE_HOCKEY_HIGHEST_SCORING_PERIOD):
		return evaluateHighestScoringPeriod(outcome, firstPeriod, secondPeriod, thirdPeriod)
	case int64(domain.ICE_HOCKEY_TIED_AFTER_REGULATION):
		return evaluateTiedAfterRegulation(outcome, regulation)
	case int64(domain.ICE_HOCKEY_GAME_TOTAL_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, finalScore)
	}

	return domain.OUTCOME_STATUS_PENDING, nil
}

func (s *Service) evaluateCricketOutcome(outcome domain.BetOutcome, res domain.CricketResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	score := parseSS(res.SS)

	switch outcome.MarketID {
	case int64(domain.CRICKET_TO_WIN_THE_MATCH):
		return evaluateFullTimeResult(outcome, score)
	}

	return domain.OUTCOME_STATUS_PENDING, nil
}

func (s *Service) evaluateVolleyballOutcome(outcome domain.BetOutcome, res domain.VolleyballResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	score := parseSS(res.SS)

	// res.SS example: { 2-3 } is the win count not actuall score of sets
	// for total score we need every set's score
	firstSet := parseScore(res.Scores.FirstSet.Home, res.Scores.FirstSet.Away)
	secondSet := parseScore(res.Scores.SecondSet.Home, res.Scores.SecondSet.Away)
	thirdSet := parseScore(res.Scores.ThirdSet.Home, res.Scores.ThirdSet.Away)
	fourthSet := parseScore(res.Scores.FourthSet.Home, res.Scores.FourthSet.Away)
	fivethSet := parseScore(res.Scores.FivethSet.Home, res.Scores.FivethSet.Away)

	totalScore := struct{ Home, Away int }{Home: 0, Away: 0}
	totalScore.Home = firstSet.Home + secondSet.Home + thirdSet.Home + fourthSet.Home + fivethSet.Home
	totalScore.Away = firstSet.Away + secondSet.Away + thirdSet.Away + fourthSet.Away + fivethSet.Away

	switch outcome.MarketID {
	case int64(domain.VOLLEYBALL_GAME_LINES):
		return evaluateVolleyballGamelines(outcome, totalScore)
	case int64(domain.VOLLEYBALL_MATCH_TOTAL_ODD_EVEN):
		return evaluateGoalsOddEven(outcome, totalScore)
	case int64(domain.VOLLEYBALL_CORRECT_SET_SCORE):
		return evaluateCorrectScore(outcome, score)
	}

	return domain.OUTCOME_STATUS_PENDING, nil
}

func (s *Service) evaluateDartsOutcome(outcome domain.BetOutcome, res domain.DartsResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	score := parseSS(res.SS)

	switch outcome.MarketID {
	case int64(domain.DARTS_MATCH_WINNER):
		return evaluateFullTimeResult(outcome, score)
	case int64(domain.DARTS_TOTAL_LEGS):
		return evaluateTotalLegs(outcome, score)
	}

	return domain.OUTCOME_STATUS_PENDING, nil
}

func (s *Service) evaluateFutsalOutcome(outcome domain.BetOutcome, res domain.FutsalResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	score := parseSS(res.SS)

	switch outcome.MarketID {
	case int64(domain.FUTSAL_GAME_LINES):
		return evaluateGameLines(outcome, score)
	case int64(domain.FUTSAL_MONEY_LINE):
		return evaluateMoneyLine(outcome, score)
	case int64(domain.FUTSAL_TEAM_TO_SCORE_FIRST):
		return evaluateFirstTeamToScore(outcome, res.Events)
	}

	return domain.OUTCOME_STATUS_PENDING, nil
}

func (s *Service) evaluateNFLOutcome(outcome domain.BetOutcome, res domain.NFLResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	finalScore := parseSS(res.SS)

	switch outcome.MarketID {
	case int64(domain.AMERICAN_FOOTBALL_GAME_LINES):
		return evaluateGameLines(outcome, finalScore)
	default:
		s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("market type not implemented: %s", outcome.MarketName)
	}
}

func (s *Service) evaluateRugbyOutcome(outcome domain.BetOutcome, result domain.RugbyResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	finalScore := parseSS(result.SS)

	switch outcome.MarketID {
	case int64(domain.RUGBY_L_GAME_BETTING_2_WAY):
		return evaluateGameBettingTwoWay(outcome, finalScore)
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported rugby market: %s", outcome.MarketName)
	}
}

func (s *Service) evaluateBaseballOutcome(outcome domain.BetOutcome, res domain.BaseballResultResponse) (domain.OutcomeStatus, error) {
	if !domain.SupportedMarkets[outcome.MarketID] {
		s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName)
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName)
	}

	finalScore := parseSS(res.SS)

	switch outcome.MarketID {
	case int64(domain.BASEBALL_GAME_LINES):
		return evaluateGameLines(outcome, finalScore)
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported baseball market: %s", outcome.MarketName)
	}
}
