package result

import (
	"fmt"
	"strconv"

	"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)

// NFL evaluations
func EvaluateNFLMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	switch outcome.OddHeader {
	case "1":
		if score.Home > score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "2":
		if score.Away > score.Home {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}
}

func EvaluateNFLSpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
	if err != nil {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
	}

	adjustedHomeScore := float64(score.Home)
	adjustedAwayScore := float64(score.Away)

	if outcome.OddHeader == "1" {
		adjustedHomeScore += handicap
	} else if outcome.OddHeader == "2" {
		adjustedAwayScore += handicap
	} else {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}

	if adjustedHomeScore > adjustedAwayScore {
		if outcome.OddHeader == "1" {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	} else if adjustedHomeScore < adjustedAwayScore {
		if outcome.OddHeader == "2" {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	}
	return domain.OUTCOME_STATUS_VOID, nil
}

func EvaluateNFLTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	totalPoints := float64(score.Home + score.Away)
	threshold, err := strconv.ParseFloat(outcome.OddName, 64)
	if err != nil {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid threshold: %s", outcome.OddName)
	}

	if outcome.OddHeader == "Over" {
		if totalPoints > threshold {
			return domain.OUTCOME_STATUS_WIN, nil
		} else if totalPoints == threshold {
			return domain.OUTCOME_STATUS_VOID, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	} else if outcome.OddHeader == "Under" {
		if totalPoints < threshold {
			return domain.OUTCOME_STATUS_WIN, nil
		} else if totalPoints == threshold {
			return domain.OUTCOME_STATUS_VOID, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	}
	return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
}

// EvaluateRugbyMoneyLine Evaluates Rugby money line bets
func EvaluateRugbyMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	switch outcome.OddHeader {
	case "1":
		if score.Home > score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "2":
		if score.Away > score.Home {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}
}

// EvaluateRugbySpread Evaluates Rugby spread bets
func EvaluateRugbySpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
	if err != nil {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
	}

	adjustedHomeScore := float64(score.Home)
	adjustedAwayScore := float64(score.Away)

	if outcome.OddHeader == "1" {
		adjustedHomeScore += handicap
	} else if outcome.OddHeader == "2" {
		adjustedAwayScore += handicap
	} else {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}

	if adjustedHomeScore > adjustedAwayScore {
		if outcome.OddHeader == "1" {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	} else if adjustedHomeScore < adjustedAwayScore {
		if outcome.OddHeader == "2" {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	}
	return domain.OUTCOME_STATUS_VOID, nil
}

// EvaluateRugbyTotalPoints Evaluates Rugby total points bets
func EvaluateRugbyTotalPoints(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	totalPoints := float64(score.Home + score.Away)
	threshold, err := strconv.ParseFloat(outcome.OddName, 64)
	if err != nil {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid threshold: %s", outcome.OddName)
	}

	if outcome.OddHeader == "Over" {
		if totalPoints > threshold {
			return domain.OUTCOME_STATUS_WIN, nil
		} else if totalPoints == threshold {
			return domain.OUTCOME_STATUS_VOID, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	} else if outcome.OddHeader == "Under" {
		if totalPoints < threshold {
			return domain.OUTCOME_STATUS_WIN, nil
		} else if totalPoints == threshold {
			return domain.OUTCOME_STATUS_VOID, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	}
	return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
}

// EvaluateBaseballMoneyLine Evaluates Baseball money line bets
func EvaluateBaseballMoneyLine(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	switch outcome.OddHeader {
	case "1":
		if score.Home > score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "2":
		if score.Away > score.Home {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}
}

// EvaluateBaseballSpread Evaluates Baseball spread bets
func EvaluateBaseballSpread(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	handicap, err := strconv.ParseFloat(outcome.OddHandicap, 64)
	if err != nil {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid handicap: %s", outcome.OddHandicap)
	}

	adjustedHomeScore := float64(score.Home)
	adjustedAwayScore := float64(score.Away)

	if outcome.OddHeader == "1" {
		adjustedHomeScore += handicap
	} else if outcome.OddHeader == "2" {
		adjustedAwayScore += handicap
	} else {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}

	if adjustedHomeScore > adjustedAwayScore {
		if outcome.OddHeader == "1" {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	} else if adjustedHomeScore < adjustedAwayScore {
		if outcome.OddHeader == "2" {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	}
	return domain.OUTCOME_STATUS_VOID, nil
}

// EvaluateBaseballTotalRuns Evaluates Baseball total runs bets
func EvaluateBaseballTotalRuns(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	totalRuns := float64(score.Home + score.Away)
	threshold, err := strconv.ParseFloat(outcome.OddName, 64)
	if err != nil {
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid threshold: %s", outcome.OddName)
	}

	if outcome.OddHeader == "Over" {
		if totalRuns > threshold {
			return domain.OUTCOME_STATUS_WIN, nil
		} else if totalRuns == threshold {
			return domain.OUTCOME_STATUS_VOID, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	} else if outcome.OddHeader == "Under" {
		if totalRuns < threshold {
			return domain.OUTCOME_STATUS_WIN, nil
		} else if totalRuns == threshold {
			return domain.OUTCOME_STATUS_VOID, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	}
	return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
}

// EvaluateBaseballFirstInning Evaluates Baseball first inning bets
func EvaluateBaseballFirstInning(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	switch outcome.OddHeader {
	case "1":
		if score.Home > score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "2":
		if score.Away > score.Home {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "X":
		if score.Home == score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}
}

// EvaluateBaseballFirst5Innings Evaluates Baseball first 5 innings bets
func EvaluateBaseballFirst5Innings(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) {
	switch outcome.OddHeader {
	case "1":
		if score.Home > score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "2":
		if score.Away > score.Home {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	case "X":
		if score.Home == score.Away {
			return domain.OUTCOME_STATUS_WIN, nil
		}
		return domain.OUTCOME_STATUS_LOSS, nil
	default:
		return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd header: %s", outcome.OddHeader)
	}
}
