package repositories

import (
	config "astrology-api/configs"
	dto "astrology-api/dto"
	models "astrology-api/models/usermodel"
	"strings"

	"gorm.io/gorm"
)

type FollowerRepository interface {

	// Follow
	AddFollowing(userID uint, astrologerID uint) (*models.UserFollowing, error)

	// Unfollow
	RemoveFollowing(userID uint, astrologerID uint) error

	// Already Followed?
	IsFollowing(userID uint, astrologerID uint) (bool, error)

	// My Following List
	GetFollowingList(userID uint, startIndex int, fetchRecord int) ([]dto.FollowingResponse, int64, error)

	// Astrologer Followers
	GetAstrologerFollowers(astrologerID uint) ([]dto.FollowerResponse, int64, error)

	// Followers Count
	GetFollowersCount(astrologerID uint) (int64, error)
}

type followerRepository struct {
	db *gorm.DB
}

func NewFollowerRepository() FollowerRepository {
	return &followerRepository{
		db: config.DB,
	}
}

func (r *followerRepository) AddFollowing(userID uint, astrologerID uint) (*models.UserFollowing, error) {

	var follow models.UserFollowing

	err := r.db.
		Where("userId=? AND astrologerId=?", userID, astrologerID).
		First(&follow).Error

	if err == nil {
		return &follow, nil
	}

	if err != nil && err != gorm.ErrRecordNotFound {
		return nil, err
	}

	// convert userID (uint) to int32 pointers if the model expects int32
	var createdBy int32 = int32(userID)
	var modifiedBy int32 = int32(userID)

	follow = models.UserFollowing{
		UserID:       userID,
		AstrologerID: astrologerID,
		IsActive:     true,
		IsDelete:     false,
		CreatedBy:    uint(createdBy),
		ModifiedBy:   uint(modifiedBy),
	}

	// Insert record
	if err := r.db.Create(&follow).Error; err != nil {
		return nil, err
	}

	// Reload record with relations
	var response models.UserFollowing

	err = r.db.
		Preload("User").
		Preload("Astrologer").
		First(&response, follow.ID).Error

	if err != nil {
		return nil, err
	}

	return &response, nil
}

func (r *followerRepository) RemoveFollowing(userID uint, astrologerID uint) error {

	return r.db.
		Where("userId=? AND astrologerId=?", userID, astrologerID).
		Delete(&models.UserFollowing{}).Error
}

func (r *followerRepository) IsFollowing(userID uint, astrologerID uint) (bool, error) {

	var count int64

	err := r.db.
		Model(&models.UserFollowing{}).
		Where("userId=? AND astrologerId=?", userID, astrologerID).
		Count(&count).Error

	return count > 0, err
}

func (r *followerRepository) GetFollowersCount(astrologerID uint) (int64, error) {

	var total int64

	err := r.db.
		Model(&models.UserFollowing{}).
		Where("astrologerId=?", astrologerID).
		Count(&total).Error

	return total, err
}

func (r *followerRepository) GetAstrologerFollowers(astrologerID uint) ([]dto.FollowerResponse, int64, error) {

	var list []dto.FollowerResponse
	var total int64

	query := r.db.
		Table("astrologer_followers").
		Joins("JOIN users ON users.id = astrologer_followers.userId").
		Where("astrologer_followers.astrologerId=?", astrologerID)

	query.Count(&total)

	err := query.
		Select(`users.id, users.name, users.profile as profileImage `).
		Scan(&list).Error

	return list, total, err
}

func (r *followerRepository) GetFollowingList(userID uint, startIndex int, fetchRecord int) ([]dto.FollowingResponse, int64, error) {

	var list []dto.FollowingResponse
	var total int64

	query := r.db.
		Table("astrologer_followers").
		Joins("JOIN astrologers ON astrologers.id = astrologer_followers.astrologerId").
		Where("astrologer_followers.userId=?", userID)

	query.Count(&total)

	if fetchRecord > 0 {
		query = query.Offset(startIndex).Limit(fetchRecord)
	}

	err := query.
		Select(`
			astrologers.id,
			astrologers.name,
			astrologers.profileImage,
			astrologers.languageKnown,
			astrologers.allSkill,
			astrologers.experience,
			astrologers.charge,
			astrologers.totalOrder,
			astrologers.rating as totalRating,
			astrologers.reportRate as averageRating,
			astrologers.isVerified
		`).
		Scan(&list).Error

	if err != nil {
		return nil, 0, err
	}

	// Convert language ids & skill ids into names
	for i := range list {

		list[i].LanguageKnown = r.getLanguageNames(list[i].LanguageKnown)

		list[i].AllSkill = r.getSkillNames(list[i].AllSkill)

		list[i].IsFollow = true
	}

	return list, total, nil
}

func (r *followerRepository) getLanguageNames(ids string) string {

	if ids == "" {
		return ""
	}

	var names []string

	r.db.
		Model(&models.Language{}).
		Where("id IN ?", strings.Split(ids, ",")).
		Pluck("languageName", &names)

	return strings.Join(names, ", ")
}

func (r *followerRepository) getSkillNames(ids string) string {

	if ids == "" {
		return ""
	}

	var names []string

	r.db.
		Model(&models.Skill{}).
		Where("id IN ?", strings.Split(ids, ",")).
		Pluck("name", &names)

	return strings.Join(names, ", ")
}
