package services

import (
	"errors"

	"gauth-central/internal/database"
	"gauth-central/internal/models"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

type UserManagementService struct{}

func NewUserManagementService() *UserManagementService {
	return &UserManagementService{}
}

var ErrUserNotFound = errors.New("user not found")

// GetAllUsers - Tüm kullanıcıları getir (admin için)
func (s *UserManagementService) GetAllUsers(page, limit int) ([]models.User, int64, error) {
	var users []models.User
	var total int64

	// Count total users
	database.DB.Model(&models.User{}).Count(&total)

	// Calculate offset
	offset := (page - 1) * limit

	// Fetch users with pagination and preload roles
	err := database.DB.
		Preload("Roles").
		Preload("SocialAccounts").
		Offset(offset).
		Limit(limit).
		Order("created_at DESC").
		Find(&users).Error

	return users, total, err
}

// GetUserByID - ID'ye göre kullanıcı getir
func (s *UserManagementService) GetUserByID(userID string) (*models.User, error) {
	var user models.User
	err := database.DB.
		Preload("Roles").
		Preload("Roles.Permissions").
		Preload("SocialAccounts").
		Where("id = ?", userID).
		First(&user).Error

	if err != nil {
		return nil, err
	}

	return &user, nil
}

// CreateUser - Yeni kullanıcı oluştur (admin tarafından)
func (s *UserManagementService) CreateUser(email, password, userName string, emailVerified bool, roleNames []string) (*models.User, error) {
	// Hash password
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return nil, err
	}

	user := &models.User{
		Email:         email,
		UserName:      userName,
		Password:      string(hashedPassword),
		EmailVerified: &emailVerified,
	}

	// Create user
	if err := database.DB.Create(user).Error; err != nil {
		return nil, err
	}

	// Assign roles
	if len(roleNames) > 0 {
		var roles []models.Role
		database.DB.Where("name IN ?", roleNames).Find(&roles)
		if len(roles) > 0 {
			database.DB.Model(user).Association("Roles").Append(roles)
		}
	} else {
		// Assign default "user" role
		var userRole models.Role
		database.DB.Where("name = ?", "user").First(&userRole)
		database.DB.Model(user).Association("Roles").Append(&userRole)
	}

	// Reload user with roles
	database.DB.Preload("Roles").Where("id = ?", user.ID).First(user)

	return user, nil
}

// UpdateUser - Kullanıcı bilgilerini güncelle
func (s *UserManagementService) UpdateUser(userID string, updates map[string]interface{}) error {
	// Check if user exists
	var user models.User
	if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil {
		return err
	}

	// If password is being updated, hash it
	if password, ok := updates["password"].(string); ok && password != "" {
		hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
		if err != nil {
			return err
		}
		updates["password"] = string(hashedPassword)
	}

	// Use Updates with Select to update specific fields including zero values
	return database.DB.Model(&user).Updates(updates).Error
}

// DeleteUser - Kullanıcıyı sil (soft delete, hard=true ise kalıcı silme)
func (s *UserManagementService) DeleteUser(userID string, hardDelete bool) error {
	if hardDelete {
		// Hard delete - ilişkili kayıtları da sil
		var user models.User
		if err := database.DB.Unscoped().Where("id = ?", userID).First(&user).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				return ErrUserNotFound
			}
			return err
		}

		// Delete relations first
		database.DB.Exec("DELETE FROM user_roles WHERE user_id = ?", userID)
		database.DB.Exec("DELETE FROM social_accounts WHERE user_id = ?", userID)

		// Permanently delete user
		result := database.DB.Unscoped().Delete(&models.User{}, "id = ?", userID)
		if result.Error != nil {
			return result.Error
		}
		if result.RowsAffected == 0 {
			return ErrUserNotFound
		}
		return nil
	}

	// Soft delete
	result := database.DB.Delete(&models.User{}, "id = ?", userID)
	if result.Error != nil {
		return result.Error
	}
	if result.RowsAffected == 0 {
		return ErrUserNotFound
	}
	return nil
}

// AssignRoles - Kullanıcıya roller ata
func (s *UserManagementService) AssignRoles(userID string, roleNames []string) error {
	var user models.User
	if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil {
		return err
	}

	var roles []models.Role
	if err := database.DB.Where("name IN ?", roleNames).Find(&roles).Error; err != nil {
		return err
	}

	if len(roles) == 0 {
		return errors.New("no valid roles found")
	}

	return database.DB.Model(&user).Association("Roles").Replace(roles)
}

// RemoveRole - Kullanıcıdan rol kaldır
func (s *UserManagementService) RemoveRole(userID string, roleName string) error {
	var user models.User
	if err := database.DB.Where("id = ?", userID).First(&user).Error; err != nil {
		return err
	}

	var role models.Role
	if err := database.DB.Where("name = ?", roleName).First(&role).Error; err != nil {
		return err
	}

	return database.DB.Model(&user).Association("Roles").Delete(&role)
}

// SearchUsers - Kullanıcı ara (email, username)
func (s *UserManagementService) SearchUsers(query string, page, limit int) ([]models.User, int64, error) {
	var users []models.User
	var total int64

	searchQuery := "%" + query + "%"

	// Count total matching users
	database.DB.Model(&models.User{}).
		Where("email ILIKE ? OR user_name ILIKE ?", searchQuery, searchQuery).
		Count(&total)

	// Calculate offset
	offset := (page - 1) * limit

	// Fetch users
	err := database.DB.
		Preload("Roles").
		Preload("SocialAccounts").
		Where("email ILIKE ? OR user_name ILIKE ?", searchQuery, searchQuery).
		Offset(offset).
		Limit(limit).
		Order("created_at DESC").
		Find(&users).Error

	return users, total, err
}

// GetDeletedUsers - Soft delete edilmiş kullanıcıları getir
func (s *UserManagementService) GetDeletedUsers(page, limit int) ([]models.User, int64, error) {
	var users []models.User
	var total int64

	// Count total deleted users
	database.DB.Model(&models.User{}).Unscoped().Where("deleted_at IS NOT NULL").Count(&total)

	// Calculate offset
	offset := (page - 1) * limit

	// Fetch deleted users with pagination
	err := database.DB.Unscoped().
		Preload("Roles").
		Preload("SocialAccounts").
		Where("deleted_at IS NOT NULL").
		Offset(offset).
		Limit(limit).
		Order("deleted_at DESC").
		Find(&users).Error

	return users, total, err
}

// RestoreUser - Soft delete edilmiş kullanıcıyı geri yükle
func (s *UserManagementService) RestoreUser(userID string) error {
	var user models.User

	// Find soft deleted user
	if err := database.DB.Unscoped().Where("id = ? AND deleted_at IS NOT NULL", userID).First(&user).Error; err != nil {
		return errors.New("deleted user not found")
	}

	// Restore user (set deleted_at to NULL)
	return database.DB.Unscoped().Model(&user).Update("deleted_at", nil).Error
}
