package repository

import (
	"context"

	"gorm.io/gorm"

	"security-center-backend/internal/model"
)

type RoleRepository interface {
	List(ctx context.Context) ([]model.Role, error)
	ListPaginated(ctx context.Context, page, pageSize int) ([]model.Role, int64, error)
	FindByID(ctx context.Context, id uint64) (*model.Role, error)
	Create(ctx context.Context, role *model.Role) error
	Update(ctx context.Context, role *model.Role) error
	Delete(ctx context.Context, id uint64) error
	AssignPermissions(ctx context.Context, roleID uint64, permissionIDs []uint64) error
	FindDefault(ctx context.Context) (*model.Role, error)
	FindByName(ctx context.Context, name string) (*model.Role, error)
	ClearDefault(ctx context.Context) error
}

type GormRoleRepository struct {
	db *gorm.DB
}

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

func (r *GormRoleRepository) List(ctx context.Context) ([]model.Role, error) {
	var roles []model.Role
	if err := r.db.WithContext(ctx).Preload("Permissions").Find(&roles).Error; err != nil {
		return nil, err
	}
	return roles, nil
}

func (r *GormRoleRepository) ListPaginated(ctx context.Context, page, pageSize int) ([]model.Role, int64, error) {
	var (
		roles []model.Role
		total int64
	)
	query := r.db.WithContext(ctx).Model(&model.Role{})
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}
	if err := query.Preload("Permissions").Limit(pageSize).Offset((page - 1) * pageSize).Find(&roles).Error; err != nil {
		return nil, 0, err
	}
	return roles, total, nil
}

func (r *GormRoleRepository) FindByID(ctx context.Context, id uint64) (*model.Role, error) {
	var role model.Role
	if err := r.db.WithContext(ctx).Preload("Permissions").First(&role, id).Error; err != nil {
		return nil, err
	}
	return &role, nil
}

func (r *GormRoleRepository) Create(ctx context.Context, role *model.Role) error {
	return r.db.WithContext(ctx).Create(role).Error
}

func (r *GormRoleRepository) Update(ctx context.Context, role *model.Role) error {
	return r.db.WithContext(ctx).Save(role).Error
}

func (r *GormRoleRepository) Delete(ctx context.Context, id uint64) error {
	return r.db.WithContext(ctx).Delete(&model.Role{}, id).Error
}

func (r *GormRoleRepository) AssignPermissions(ctx context.Context, roleID uint64, permissionIDs []uint64) error {
	var role model.Role
	if err := r.db.WithContext(ctx).First(&role, roleID).Error; err != nil {
		return err
	}
	var permissions []model.Permission
	if err := r.db.WithContext(ctx).Find(&permissions, permissionIDs).Error; err != nil {
		return err
	}
	return r.db.WithContext(ctx).Model(&role).Association("Permissions").Replace(permissions)
}

func (r *GormRoleRepository) FindDefault(ctx context.Context) (*model.Role, error) {
	var role model.Role
	if err := r.db.WithContext(ctx).Preload("Permissions").Where("is_default = ?", true).First(&role).Error; err != nil {
		return nil, err
	}
	return &role, nil
}

func (r *GormRoleRepository) FindByName(ctx context.Context, name string) (*model.Role, error) {
	var role model.Role
	if err := r.db.WithContext(ctx).Preload("Permissions").Where("name = ?", name).First(&role).Error; err != nil {
		return nil, err
	}
	return &role, nil
}

func (r *GormRoleRepository) ClearDefault(ctx context.Context) error {
	return r.db.WithContext(ctx).Model(&model.Role{}).Where("is_default = ?", true).Update("is_default", false).Error
}
