package repositories_astrologer

import (
	config "astrology-api/configs"
	models "astrology-api/models/astrologermodel"
	"errors"
	"time"

	"gorm.io/gorm"
)

type statisticsRepository struct {
	db *gorm.DB
}

func NewStatisticsRepository() StatisticsRepository {

	return &statisticsRepository{
		db: config.DB,
	}
}

func NewStatisticsRepositoryWithDB(db *gorm.DB) StatisticsRepository {
	return &statisticsRepository{
		db: db,
	}
}

func (r *statisticsRepository) GetTodayStatistics(astrologerID uint) (*models.AstrologerDailyStatistics, error) {

	var statistics models.AstrologerDailyStatistics

	today := time.Now().Format("2006-01-02")

	err := r.db.
		Where("astrologer_id = ?", astrologerID).
		Where("DATE(statistic_date) = ?", today).
		Where("is_delete = ?", false).
		First(&statistics).Error

	if err != nil {

		if errors.Is(err, gorm.ErrRecordNotFound) {

			now := time.Now()

			statistics = models.AstrologerDailyStatistics{

				AstrologerID:  astrologerID,
				StatisticDate: now,

				OnlineMinutes: 0,

				TotalCalls:     0,
				CompletedCalls: 0,
				MissedCalls:    0,
				CancelledCalls: 0,

				TotalChats:     0,
				CompletedChats: 0,
				MissedChats:    0,
				CancelledChats: 0,

				TotalCallMinutes: 0,
				TotalChatMinutes: 0,

				CallEarning:   0,
				ChatEarning:   0,
				ReportEarning: 0,
				GiftEarning:   0,
				TotalEarning:  0,

				AverageRating:  0,
				TotalReviews:   0,
				AcceptanceRate: 0,
				ResponseRate:   0,

				IsActive:  true,
				IsDelete:  false,
				CreatedAt: &now,
				UpdatedAt: &now,
			}

			if err := r.db.Create(&statistics).Error; err != nil {
				return nil, err
			}

			return &statistics, nil
		}

		return nil, err
	}

	return &statistics, nil
}

func (r *statisticsRepository) GetStatisticsByID(id uint) (*models.AstrologerDailyStatistics, error) {

	var statistics models.AstrologerDailyStatistics

	err := r.db.
		Where("id = ?", id).
		Where("is_delete = ?", false).
		First(&statistics).Error

	if err != nil {
		return nil, err
	}

	return &statistics, nil
}

func (r *statisticsRepository) GetStatisticsByDate(astrologerID uint, date time.Time) (*models.AstrologerDailyStatistics, error) {
	var statistics models.AstrologerDailyStatistics
	err := r.db.
		Where("astrologer_id = ?", astrologerID).
		Where("DATE(statistic_date)=?", date.Format("2006-01-02")).
		Where("is_delete = ?", false).
		First(&statistics).Error

	if err != nil {
		return nil, err
	}
	return &statistics, nil
}

func (r *statisticsRepository) CreateTodayStatistics(stats *models.AstrologerDailyStatistics) error {
	if stats == nil {
		return errors.New("statistics cannot be nil")
	}
	now := time.Now()
	if stats.CreatedAt == nil {
		stats.CreatedAt = &now
	}
	if stats.UpdatedAt == nil {
		stats.UpdatedAt = &now
	}
	stats.IsActive = true
	stats.IsDelete = false
	return r.db.Create(stats).Error
}

func (r *statisticsRepository) UpdateTodayStatistics(
	stats *models.AstrologerDailyStatistics,
) error {

	if stats == nil {
		return errors.New("statistics cannot be nil")
	}

	now := time.Now()
	stats.UpdatedAt = &now

	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Where("is_delete = ?", false).
		Updates(stats).Error
}

func (r *statisticsRepository) DeleteStatistics(
	id uint,
) error {

	now := time.Now()

	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", id).
		Updates(map[string]interface{}{
			"is_active":  false,
			"is_delete":  true,
			"updated_at": &now,
		}).Error
}

func (r *statisticsRepository) UpdateOnlineMinutes(
	astrologerID uint,
	minutes int,
) error {

	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}

	now := time.Now()

	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"online_minutes": gorm.Expr("online_minutes + ?", minutes),
			"updated_at":     &now,
		}).Error
}

func (r *statisticsRepository) IncrementChatCount(astrologerID uint) error {
	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}
	now := time.Now()
	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"total_chats":     gorm.Expr("total_chats + ?", 1),
			"completed_chats": gorm.Expr("completed_chats + ?", 1),
			"updated_at":      &now,
		}).Error
}

func (r *statisticsRepository) IncrementCallCount(
	astrologerID uint,
) error {

	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}

	now := time.Now()

	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"total_calls":     gorm.Expr("total_calls + ?", 1),
			"completed_calls": gorm.Expr("completed_calls + ?", 1),
			"updated_at":      &now,
		}).Error
}

func (r *statisticsRepository) UpdateEarnings(astrologerID uint, amount float64) error {
	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}
	now := time.Now()
	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"total_earning": gorm.Expr("total_earning + ?", amount),
			"updated_at":    &now,
		}).Error
}

func (r *statisticsRepository) UpdateRating(
	astrologerID uint,
	rating float64,
) error {
	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}
	totalReviews := stats.TotalReviews + 1
	averageRating := rating
	if stats.TotalReviews > 0 {
		averageRating =
			((stats.AverageRating * float64(stats.TotalReviews)) + rating) /
				float64(totalReviews)
	}

	now := time.Now()
	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"average_rating": averageRating,
			"total_reviews":  totalReviews,
			"updated_at":     &now,
		}).Error
}

func (r *statisticsRepository) UpdateAcceptanceRate(astrologerID uint, rate float64) error {
	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}
	now := time.Now()
	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"acceptance_rate": rate,
			"updated_at":      &now,
		}).Error
}

func (r *statisticsRepository) UpdateResponseRate(astrologerID uint, rate float64) error {
	stats, err := r.GetTodayStatistics(astrologerID)
	if err != nil {
		return err
	}
	now := time.Now()
	return r.db.
		Model(&models.AstrologerDailyStatistics{}).
		Where("id = ?", stats.ID).
		Updates(map[string]interface{}{
			"response_rate": rate,
			"updated_at":    &now,
		}).Error
}

func (r *statisticsRepository) GetDashboardStatistics(astrologerID uint) (*models.AstrologerDailyStatistics, error) {
	var statistics models.AstrologerDailyStatistics
	err := r.db.
		Where("astrologer_id = ?", astrologerID).
		Where("is_delete = ?", false).
		Order("statistic_date DESC").
		First(&statistics).Error
	if err != nil {
		return nil, err
	}
	return &statistics, nil
}
