// repositories/achievement_repository.go
package repository

import (
	"time"

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

type AchievementRepository interface {
	Create(achievement *models.Achievement) error
	GetByID(id uint) (*models.Achievement, error)
	GetByUserID(userID uint) ([]models.Achievement, error)
	GetByUserAndType(userID uint, achievementType models.AchievementType) ([]models.Achievement, error)
	GetVerifiedByUserID(userID uint) ([]models.Achievement, error)
	GetByDateRange(userID uint, startDate, endDate time.Time) ([]models.Achievement, error)
	Update(achievement *models.Achievement) error
	Delete(id uint) error
	VerifyAchievement(id uint) error
	GetUserAchievementsSummary(userID uint) (*models.UserAchievementsResponse, error)
	GetRecentAchievements(userID uint, limit int) ([]models.Achievement, error)
	CountByType(userID uint) (map[models.AchievementType]int64, error)
	ExistsByTitleAndUser(userID uint, title string) (bool, error)
}

type achievementRepository struct {
	db *gorm.DB
}

func NewAchievementRepository(db *gorm.DB) AchievementRepository {
	return &achievementRepository{db: db}
}

// Create создает новое достижение
func (r *achievementRepository) Create(achievement *models.Achievement) error {
	return r.db.Create(achievement).Error
}

// GetByID возвращает достижение по ID
func (r *achievementRepository) GetByID(id uint) (*models.Achievement, error) {
	var achievement models.Achievement
	err := r.db.Preload("User").First(&achievement, id).Error
	if err != nil {
		return nil, err
	}
	return &achievement, nil
}

// GetByUserID возвращает все достижения пользователя
func (r *achievementRepository) GetByUserID(userID uint) ([]models.Achievement, error) {
	var achievements []models.Achievement
	err := r.db.Where("user_id = ?", userID).
		Order("date DESC, created_at DESC").
		Find(&achievements).Error
	if err != nil {
		return nil, err
	}
	return achievements, nil
}

// GetByUserAndType возвращает достижения пользователя по типу
func (r *achievementRepository) GetByUserAndType(userID uint, achievementType models.AchievementType) ([]models.Achievement, error) {
	var achievements []models.Achievement
	err := r.db.Where("user_id = ? AND type = ?", userID, achievementType).
		Order("date DESC").
		Find(&achievements).Error
	if err != nil {
		return nil, err
	}
	return achievements, nil
}

// GetVerifiedByUserID возвращает подтвержденные достижения пользователя
func (r *achievementRepository) GetVerifiedByUserID(userID uint) ([]models.Achievement, error) {
	var achievements []models.Achievement
	err := r.db.Where("user_id = ? AND verified = ?", userID, true).
		Order("date DESC").
		Find(&achievements).Error
	if err != nil {
		return nil, err
	}
	return achievements, nil
}

// GetByDateRange возвращает достижения за период времени
func (r *achievementRepository) GetByDateRange(userID uint, startDate, endDate time.Time) ([]models.Achievement, error) {
	var achievements []models.Achievement
	err := r.db.Where("user_id = ? AND date BETWEEN ? AND ?", userID, startDate, endDate).
		Order("date DESC").
		Find(&achievements).Error
	if err != nil {
		return nil, err
	}
	return achievements, nil
}

// Update обновляет достижение
func (r *achievementRepository) Update(achievement *models.Achievement) error {
	return r.db.Save(achievement).Error
}

// Delete удаляет достижение
func (r *achievementRepository) Delete(id uint) error {
	return r.db.Delete(&models.Achievement{}, id).Error
}

// VerifyAchievement подтверждает достижение
func (r *achievementRepository) VerifyAchievement(id uint) error {
	return r.db.Model(&models.Achievement{}).
		Where("id = ?", id).
		Update("verified", true).
		Error
}

// GetUserAchievementsSummary возвращает сводку по достижениям пользователя
func (r *achievementRepository) GetUserAchievementsSummary(userID uint) (*models.UserAchievementsResponse, error) {
	var totalCount int64
	var verifiedCount int64

	// Считаем общее количество достижений
	err := r.db.Model(&models.Achievement{}).
		Where("user_id = ?", userID).
		Count(&totalCount).Error
	if err != nil {
		return nil, err
	}

	// Считаем количество подтвержденных достижений
	err = r.db.Model(&models.Achievement{}).
		Where("user_id = ? AND verified = ?", userID, true).
		Count(&verifiedCount).Error
	if err != nil {
		return nil, err
	}

	// Получаем все достижения пользователя
	achievements, err := r.GetByUserID(userID)
	if err != nil {
		return nil, err
	}

	// Вычисляем процент прогресса
	progressPercent := 0.0
	if totalCount > 0 {
		progressPercent = (float64(verifiedCount) / float64(totalCount)) * 100
	}

	return &models.UserAchievementsResponse{
		TotalAchievements: int(totalCount),
		Completed:         int(verifiedCount),
		ProgressPercent:   progressPercent,
		Achievements:      achievements,
	}, nil
}

// GetRecentAchievements возвращает последние достижения пользователя
func (r *achievementRepository) GetRecentAchievements(userID uint, limit int) ([]models.Achievement, error) {
	var achievements []models.Achievement
	err := r.db.Where("user_id = ?", userID).
		Order("created_at DESC").
		Limit(limit).
		Find(&achievements).Error
	if err != nil {
		return nil, err
	}
	return achievements, nil
}

// CountByType возвращает количество достижений по типам
func (r *achievementRepository) CountByType(userID uint) (map[models.AchievementType]int64, error) {
	type CountResult struct {
		Type  models.AchievementType
		Count int64
	}

	var results []CountResult
	err := r.db.Model(&models.Achievement{}).
		Select("type, COUNT(*) as count").
		Where("user_id = ?", userID).
		Group("type").
		Scan(&results).Error
	if err != nil {
		return nil, err
	}

	counts := make(map[models.AchievementType]int64)
	for _, result := range results {
		counts[result.Type] = result.Count
	}

	return counts, nil
}

// ExistsByTitleAndUser проверяет, существует ли достижение с таким названием у пользователя
func (r *achievementRepository) ExistsByTitleAndUser(userID uint, title string) (bool, error) {
	var count int64
	err := r.db.Model(&models.Achievement{}).
		Where("user_id = ? AND title = ?", userID, title).
		Count(&count).Error
	if err != nil {
		return false, err
	}
	return count > 0, nil
}

// GetUnverifiedAchievements возвращает неподтвержденные достижения
func (r *achievementRepository) GetUnverifiedAchievements(userID uint) ([]models.Achievement, error) {
	var achievements []models.Achievement
	err := r.db.Where("user_id = ? AND verified = ?", userID, false).
		Order("created_at DESC").
		Find(&achievements).Error
	if err != nil {
		return nil, err
	}
	return achievements, nil
}

// GetAchievementsWithPagination возвращает достижения с пагинацией
func (r *achievementRepository) GetAchievementsWithPagination(userID uint, page, pageSize int) ([]models.Achievement, int64, error) {
	var achievements []models.Achievement
	var totalCount int64

	// Считаем общее количество
	err := r.db.Model(&models.Achievement{}).
		Where("user_id = ?", userID).
		Count(&totalCount).Error
	if err != nil {
		return nil, 0, err
	}

	// Получаем данные с пагинацией
	offset := (page - 1) * pageSize
	err = r.db.Where("user_id = ?", userID).
		Order("date DESC, created_at DESC").
		Offset(offset).
		Limit(pageSize).
		Find(&achievements).Error
	if err != nil {
		return nil, 0, err
	}

	return achievements, totalCount, nil
}