// repositories/personal_best_repository.go
package repository

import (
	"time"

	"api_bb/internal/models"
	"api_bb/pkg/utils"
	"gorm.io/gorm"
)

type PersonalBestRepository interface {
	Create(personalBest *models.PersonalBest) error
	GetByID(id uint) (*models.PersonalBest, error)
	GetByUserID(userID uint) ([]models.PersonalBest, error)
	GetByUserAndDistance(userID uint, distanceType models.DistanceType) ([]models.PersonalBest, error)
	GetBestByDistance(userID uint, distanceType models.DistanceType) (*models.PersonalBest, error)
	Update(personalBest *models.PersonalBest) error
	Delete(id uint) error
	GetVerifiedByUserID(userID uint) ([]models.PersonalBest, error)
	GetByDateRange(userID uint, startDate, endDate time.Time) ([]models.PersonalBest, error)
	GetPersonalBestsSummary(userID uint) (*models.PersonalBestsSummary, error)
	ExistsBetterTime(userID uint, distanceType models.DistanceType, time string) (bool, error)
	CalculatePace(timeStr string, distanceType models.DistanceType) (string, error)
	GetRecentPersonalBests(userID uint, limit int) ([]models.PersonalBest, error)
	GetByEventName(userID uint, eventName string) ([]models.PersonalBest, error)
}

type personalBestRepository struct {
	db *gorm.DB
}

func NewPersonalBestRepository(db *gorm.DB) PersonalBestRepository {
	return &personalBestRepository{db: db}
}

// Create создает новый личный рекорд
func (r *personalBestRepository) Create(personalBest *models.PersonalBest) error {
	return r.db.Create(personalBest).Error
}

// GetByID возвращает личный рекорд по ID
func (r *personalBestRepository) GetByID(id uint) (*models.PersonalBest, error) {
	var personalBest models.PersonalBest
	err := r.db.Preload("User").First(&personalBest, id).Error
	if err != nil {
		return nil, err
	}
	return &personalBest, nil
}

// GetByUserID возвращает все личные рекорды пользователя
func (r *personalBestRepository) GetByUserID(userID uint) ([]models.PersonalBest, error) {
	var personalBests []models.PersonalBest
	err := r.db.Where("user_id = ?", userID).
		Preload("User").
		Order("distance_type, time").
		Find(&personalBests).Error
	if err != nil {
		return nil, err
	}
	return personalBests, nil
}

// GetByUserAndDistance возвращает личные рекорды пользователя по дистанции
func (r *personalBestRepository) GetByUserAndDistance(userID uint, distanceType models.DistanceType) ([]models.PersonalBest, error) {
	var personalBests []models.PersonalBest
	err := r.db.Where("user_id = ? AND distance_type = ?", userID, distanceType).
		Preload("User").
		Order("time").
		Find(&personalBests).Error
	if err != nil {
		return nil, err
	}
	return personalBests, nil
}

// GetBestByDistance возвращает лучший результат пользователя на дистанции
func (r *personalBestRepository) GetBestByDistance(userID uint, distanceType models.DistanceType) (*models.PersonalBest, error) {
	var personalBest models.PersonalBest
	err := r.db.Where("user_id = ? AND distance_type = ?", userID, distanceType).
		Preload("User").
		Order("time").
		First(&personalBest).Error
	if err != nil {
		return nil, err
	}
	return &personalBest, nil
}

// Update обновляет личный рекорд
func (r *personalBestRepository) Update(personalBest *models.PersonalBest) error {
	return r.db.Save(personalBest).Error
}

// Delete удаляет личный рекорд
func (r *personalBestRepository) Delete(id uint) error {
	return r.db.Delete(&models.PersonalBest{}, id).Error
}

// GetVerifiedByUserID возвращает подтвержденные личные рекорды пользователя
func (r *personalBestRepository) GetVerifiedByUserID(userID uint) ([]models.PersonalBest, error) {
	var personalBests []models.PersonalBest
	err := r.db.Where("user_id = ? AND verified = ?", userID, true).
		Preload("User").
		Order("distance_type, time").
		Find(&personalBests).Error
	if err != nil {
		return nil, err
	}
	return personalBests, nil
}

// GetByDateRange возвращает личные рекорды за период времени
func (r *personalBestRepository) GetByDateRange(userID uint, startDate, endDate time.Time) ([]models.PersonalBest, error) {
	var personalBests []models.PersonalBest
	err := r.db.Where("user_id = ? AND date BETWEEN ? AND ?", userID, startDate, endDate).
		Preload("User").
		Order("date DESC, distance_type").
		Find(&personalBests).Error
	if err != nil {
		return nil, err
	}
	return personalBests, nil
}

// GetRecentPersonalBests возвращает последние личные рекорды
func (r *personalBestRepository) GetRecentPersonalBests(userID uint, limit int) ([]models.PersonalBest, error) {
	var personalBests []models.PersonalBest
	err := r.db.Where("user_id = ?", userID).
		Preload("User").
		Order("created_at DESC").
		Limit(limit).
		Find(&personalBests).Error
	if err != nil {
		return nil, err
	}
	return personalBests, nil
}

// GetByEventName возвращает личные рекорды по названию события
func (r *personalBestRepository) GetByEventName(userID uint, eventName string) ([]models.PersonalBest, error) {
	var personalBests []models.PersonalBest
	err := r.db.Where("user_id = ? AND event_name LIKE ?", userID, "%"+eventName+"%").
		Preload("User").
		Order("date DESC").
		Find(&personalBests).Error
	if err != nil {
		return nil, err
	}
	return personalBests, nil
}

// GetPersonalBestsSummary возвращает сводку лучших результатов по дистанциям
// GetPersonalBestsSummary возвращает сводку лучших результатов по дистанциям
func (r *personalBestRepository) GetPersonalBestsSummary(userID uint) (*models.PersonalBestsSummary, error) {
	summary := &models.PersonalBestsSummary{}

	// Получаем лучший результат для каждой дистанции
	distances := []models.DistanceType{
		models.Distance5K,
		models.Distance10K,
		models.DistanceHalf,
		models.DistanceFull,
	}

	for _, distance := range distances {
		best, err := r.GetBestByDistance(userID, distance)
		if err != nil && err != gorm.ErrRecordNotFound {
			return nil, err
		}
		if best != nil {
			switch distance {
			case models.Distance5K:
				summary.Best5K = best.Time
				summary.Best5KPace = best.Pace
			case models.Distance10K:
				summary.Best10K = best.Time
				summary.Best10KPace = best.Pace
			case models.DistanceHalf:
				summary.BestHalf = best.Time
				summary.BestHalfPace = best.Pace
			case models.DistanceFull:
				summary.BestMarathon = best.Time
				summary.BestMarathonPace = best.Pace
			}
		}
	}

	return summary, nil
}

// ExistsBetterTime проверяет, есть ли у пользователя уже лучший результат на этой дистанции
func (r *personalBestRepository) ExistsBetterTime(userID uint, distanceType models.DistanceType, time string) (bool, error) {
	var count int64
	err := r.db.Model(&models.PersonalBest{}).
		Where("user_id = ? AND distance_type = ? AND time < ?", userID, distanceType, time).
		Count(&count).Error
	if err != nil {
		return false, err
	}
	return count > 0, nil
}

// CalculatePace вычисляет темп на основе времени и дистанции
func (r *personalBestRepository) CalculatePace(timeStr string, distanceType models.DistanceType) (string, error) {
	// Парсим время из строки "HH:MM:SS"
	t, err := time.Parse("15:04:05", timeStr)
	if err != nil {
		return "", err
	}

	// Преобразуем в секунды
	totalSeconds := t.Hour()*3600 + t.Minute()*60 + t.Second()

	// Определяем дистанцию в метрах
	var distanceMeters float64
	switch distanceType {
	case models.Distance5K:
		distanceMeters = 5000
	case models.Distance10K:
		distanceMeters = 10000
	case models.DistanceHalf:
		distanceMeters = 21097.5 // 21.0975 km
	case models.DistanceFull:
		distanceMeters = 42195 // 42.195 km
	default:
		return "", nil // Для других дистанций не вычисляем темп
	}

	// Вычисляем темп в секундах на километр
	paceSecondsPerKm := float64(totalSeconds) / (distanceMeters / 1000)

	// Форматируем темп в "MM:SS"
	minutes := int(paceSecondsPerKm) / 60
	seconds := int(paceSecondsPerKm) % 60

	return utils.FormatPace(minutes, seconds), nil
}
