// repositories/workout_repository.go
package repository

import (
	"api_bb/internal/models"
	"errors"
	"fmt"
	"time"

	"gorm.io/gorm"
)

type WorkoutRepository interface {
	Create(workout *models.Workout) error
	FindByID(id uint) (*models.Workout, error)
	FindByUserID(userID uint) ([]models.Workout, error)
	Update(workout *models.Workout) error
	Delete(id uint) error
	GetWorkoutStats(userID uint) (*models.WorkoutStatsResponse, error)
	FindByDateRange(userID uint, startDate, endDate time.Time) ([]models.Workout, error)
	GetMonthlyStats(userID uint, year int) ([]models.MonthlyStat, error)
	GetLatestWorkouts(userID uint, limit int) ([]models.Workout, error)
	GetByType(userID uint, workoutType models.WorkoutType) ([]models.Workout, error)
}

type workoutRepository struct {
	db *gorm.DB
}

var (
	ErrNotFound = errors.New("record not found")
)

func NewWorkoutRepository(db *gorm.DB) WorkoutRepository {
	return &workoutRepository{db: db}
}

func (r *workoutRepository) Create(workout *models.Workout) error {
	return r.db.Create(workout).Error
}

func (r *workoutRepository) FindByID(id uint) (*models.Workout, error) {
	var workout models.Workout
	err := r.db.Preload("User").First(&workout, id).Error
	if err != nil {
		return nil, err
	}
	return &workout, nil
}

func (r *workoutRepository) FindByUserID(userID uint) ([]models.Workout, error) {
	var workouts []models.Workout
	err := r.db.Preload("User").Where("user_id = ?", userID).Order("date DESC").Find(&workouts).Error
	if err != nil {
		return nil, err
	}
	return workouts, nil
}

func (r *workoutRepository) Update(workout *models.Workout) error {
	return r.db.Save(workout).Error
}

func (r *workoutRepository) Delete(id uint) error {
	return r.db.Delete(&models.Workout{}, id).Error
}

func (r *workoutRepository) GetWorkoutStats(userID uint) (*models.WorkoutStatsResponse, error) {
	var stats models.WorkoutStatsResponse

	// Получаем общее количество тренировок
	var totalWorkouts int64
	if err := r.db.Model(&models.Workout{}).Where("user_id = ?", userID).Count(&totalWorkouts).Error; err != nil {
		return nil, err
	}
	stats.TotalWorkouts = int(totalWorkouts)

	// Получаем общую дистанцию
	var totalDistance struct{ Total float64 }
	if err := r.db.Model(&models.Workout{}).Where("user_id = ?", userID).Select("COALESCE(SUM(distance_km), 0) as total").Scan(&totalDistance).Error; err != nil {
		return nil, err
	}
	stats.TotalDistance = totalDistance.Total

	// Получаем общее время
	var totalTime struct{ Total int }
	if err := r.db.Model(&models.Workout{}).Where("user_id = ?", userID).Select("COALESCE(SUM(duration_min), 0) as total").Scan(&totalTime).Error; err != nil {
		return nil, err
	}
	stats.TotalTime = totalTime.Total

	// Получаем месячную статистику
	monthlyStats, err := r.GetMonthlyStats(userID, time.Now().Year())
	if err != nil {
		return nil, err
	}
	stats.MonthlyStats = monthlyStats

	// Рассчитываем средний темп (упрощенная версия)
	if totalDistance.Total > 0 && totalTime.Total > 0 {
		avgPaceMinPerKm := float64(totalTime.Total) / totalDistance.Total
		minutes := int(avgPaceMinPerKm)
		seconds := int((avgPaceMinPerKm - float64(minutes)) * 60)
		stats.AveragePace = fmt.Sprintf("%d:%02d", minutes, seconds)
	} else {
		stats.AveragePace = "0:00"
	}

	return &stats, nil
}

func (r *workoutRepository) FindByDateRange(userID uint, startDate, endDate time.Time) ([]models.Workout, error) {
	var workouts []models.Workout
	err := r.db.Preload("User").
		Where("user_id = ? AND date BETWEEN ? AND ?", userID, startDate, endDate).
		Order("date DESC").
		Find(&workouts).Error
	if err != nil {
		return nil, err
	}
	return workouts, nil
}

func (r *workoutRepository) GetMonthlyStats(userID uint, year int) ([]models.MonthlyStat, error) {
	var monthlyStats []models.MonthlyStat

	query := `
		SELECT 
			TO_CHAR(date, 'YYYY-MM') as month,
			COALESCE(SUM(distance_km), 0) as distance,
			COUNT(*) as workouts
		FROM workouts 
		WHERE user_id = ? AND EXTRACT(YEAR FROM date) = ?
		GROUP BY TO_CHAR(date, 'YYYY-MM')
		ORDER BY month DESC
	`

	err := r.db.Raw(query, userID, year).Scan(&monthlyStats).Error
	if err != nil {
		return nil, err
	}

	return monthlyStats, nil
}

func (r *workoutRepository) GetLatestWorkouts(userID uint, limit int) ([]models.Workout, error) {
	var workouts []models.Workout
	err := r.db.Preload("User").
		Where("user_id = ?", userID).
		Order("date DESC").
		Limit(limit).
		Find(&workouts).Error
	if err != nil {
		return nil, err
	}
	return workouts, nil
}

func (r *workoutRepository) GetByType(userID uint, workoutType models.WorkoutType) ([]models.Workout, error) {
	var workouts []models.Workout
	err := r.db.Preload("User").
		Where("user_id = ? AND type = ?", userID, workoutType).
		Order("date DESC").
		Find(&workouts).Error
	if err != nil {
		return nil, err
	}
	return workouts, nil
}
