package repositories

import (
	"errors"
	"lost-and-found/internal/models"

	"gorm.io/gorm"
)

type RoleRepository struct {
	db *gorm.DB
}

func NewRoleRepository(db *gorm.DB) *RoleRepository {
	return &RoleRepository{db: db}
}

// FindAllWithPermissions returns all roles with their permissions (for Role Management)
func (r *RoleRepository) FindAllWithPermissions() ([]models.Role, error) {
	var roles []models.Role
	err := r.db.Preload("Permissions").Find(&roles).Error
	return roles, err
}

// FindAllPermissions gets list of all available permissions
func (r *RoleRepository) FindAllPermissions() ([]models.Permission, error) {
	var permissions []models.Permission
	err := r.db.Find(&permissions).Error
	return permissions, err
}

// Create creates a new role
func (r *RoleRepository) Create(role *models.Role) error {
	return r.db.Create(role).Error
}

// FindByID finds role by ID with permissions loaded
func (r *RoleRepository) FindByID(id uint) (*models.Role, error) {
	var role models.Role
	err := r.db.Preload("Permissions").First(&role, id).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("role not found")
		}
		return nil, err
	}
	return &role, nil
}

// ✅ [PERBAIKAN] Menambahkan kembali method FindByName yang hilang
// FindByName finds role by name (Required by AuthService)
func (r *RoleRepository) FindByName(name string) (*models.Role, error) {
	var role models.Role
	err := r.db.Where("name = ?", name).First(&role).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errors.New("role not found")
		}
		return nil, err
	}
	return &role, nil
}

// UpdatePermissions syncs permissions for a role (Update logic)
func (r *RoleRepository) UpdatePermissions(role *models.Role, permissionIDs []uint) error {
	return r.db.Transaction(func(tx *gorm.DB) error {
		// 1. Update basic info (name/desc)
		if err := tx.Save(role).Error; err != nil {
			return err
		}

		// 2. Fetch permission objects based on IDs
		var permissions []models.Permission
		if len(permissionIDs) > 0 {
			if err := tx.Where("id IN ?", permissionIDs).Find(&permissions).Error; err != nil {
				return err
			}
		}

		// 3. Replace associations (Hapus yang lama, set yang baru)
		return tx.Model(role).Association("Permissions").Replace(permissions)
	})
}

// Delete deletes a role
func (r *RoleRepository) Delete(id uint) error {
	// Hapus relasi di role_permissions dulu (GORM biasanya handle ini via foreign key constraint, tapi untuk aman bisa manual)
	// Kita gunakan Unscoped atau Select clause jika perlu, tapi standard delete object sudah cukup jika constraint DB benar.
	return r.db.Select("Permissions").Delete(&models.Role{ID: id}).Error
}