package repository

import (
	"context"

	"gorm.io/gorm"

	"github.com/user-management-system/internal/domain"
)

// PermissionRepository 权限数据访问层
type PermissionRepository struct {
	db *gorm.DB
}

// NewPermissionRepository 创建权限数据访问层
func NewPermissionRepository(db *gorm.DB) *PermissionRepository {
	return &PermissionRepository{db: db}
}

// Create 创建权限
func (r *PermissionRepository) Create(ctx context.Context, permission *domain.Permission) error {
	// GORM omits zero values on insert for fields with DB defaults. Explicitly
	// backfill disabled status so callers can persist status=0 permissions.
	requestedStatus := permission.Status
	return r.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(permission).Error; err != nil {
			return err
		}
		if requestedStatus == domain.PermissionStatusDisabled {
			if err := tx.Model(&domain.Permission{}).Where("id = ?", permission.ID).Update("status", requestedStatus).Error; err != nil {
				return err
			}
			permission.Status = requestedStatus
		}
		return nil
	})
}

// Update 更新权限
func (r *PermissionRepository) Update(ctx context.Context, permission *domain.Permission) error {
	return r.db.WithContext(ctx).Save(permission).Error
}

// Delete 删除权限
func (r *PermissionRepository) Delete(ctx context.Context, id int64) error {
	return r.db.WithContext(ctx).Delete(&domain.Permission{}, id).Error
}

// GetByID 根据ID获取权限
func (r *PermissionRepository) GetByID(ctx context.Context, id int64) (*domain.Permission, error) {
	var permission domain.Permission
	err := r.db.WithContext(ctx).First(&permission, id).Error
	if err != nil {
		return nil, err
	}
	return &permission, nil
}

// GetByCode 根据代码获取权限
func (r *PermissionRepository) GetByCode(ctx context.Context, code string) (*domain.Permission, error) {
	var permission domain.Permission
	err := r.db.WithContext(ctx).Where("code = ?", code).First(&permission).Error
	if err != nil {
		return nil, err
	}
	return &permission, nil
}

// List 获取权限列表
func (r *PermissionRepository) List(ctx context.Context, offset, limit int) ([]*domain.Permission, int64, error) {
	var permissions []*domain.Permission
	var total int64

	query := r.db.WithContext(ctx).Model(&domain.Permission{})

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取列表
	if err := query.Offset(offset).Limit(limit).Find(&permissions).Error; err != nil {
		return nil, 0, err
	}

	return permissions, total, nil
}

// ListByType 根据类型获取权限列表
func (r *PermissionRepository) ListByType(ctx context.Context, permissionType domain.PermissionType, offset, limit int) ([]*domain.Permission, int64, error) {
	var permissions []*domain.Permission
	var total int64

	query := r.db.WithContext(ctx).Model(&domain.Permission{}).Where("type = ?", permissionType)

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取列表
	if err := query.Offset(offset).Limit(limit).Find(&permissions).Error; err != nil {
		return nil, 0, err
	}

	return permissions, total, nil
}

// ListByStatus 根据状态获取权限列表
func (r *PermissionRepository) ListByStatus(ctx context.Context, status domain.PermissionStatus, offset, limit int) ([]*domain.Permission, int64, error) {
	var permissions []*domain.Permission
	var total int64

	query := r.db.WithContext(ctx).Model(&domain.Permission{}).Where("status = ?", status)

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取列表
	if err := query.Offset(offset).Limit(limit).Find(&permissions).Error; err != nil {
		return nil, 0, err
	}

	return permissions, total, nil
}

// GetByRoleIDs 根据角色ID获取权限列表
func (r *PermissionRepository) GetByRoleIDs(ctx context.Context, roleIDs []int64) ([]*domain.Permission, error) {
	var permissions []*domain.Permission

	err := r.db.WithContext(ctx).
		Joins("INNER JOIN role_permissions ON permissions.id = role_permissions.permission_id").
		Where("role_permissions.role_id IN ?", roleIDs).
		Where("permissions.status = ?", domain.PermissionStatusEnabled).
		Find(&permissions).Error
	if err != nil {
		return nil, err
	}

	return permissions, nil
}

// ExistsByCode 检查权限代码是否存在
func (r *PermissionRepository) ExistsByCode(ctx context.Context, code string) (bool, error) {
	var count int64
	err := r.db.WithContext(ctx).Model(&domain.Permission{}).Where("code = ?", code).Count(&count).Error
	return count > 0, err
}

// UpdateStatus 更新权限状态
func (r *PermissionRepository) UpdateStatus(ctx context.Context, id int64, status domain.PermissionStatus) error {
	return r.db.WithContext(ctx).Model(&domain.Permission{}).Where("id = ?", id).Update("status", status).Error
}

// Search 搜索权限
func (r *PermissionRepository) Search(ctx context.Context, keyword string, offset, limit int) ([]*domain.Permission, int64, error) {
	var permissions []*domain.Permission
	var total int64

	// 转义 LIKE 特殊字符，防止搜索被意外干扰
	escapedKeyword := escapeLikePattern(keyword)
	pattern := "%" + escapedKeyword + "%"

	query := r.db.WithContext(ctx).Model(&domain.Permission{}).
		Where("name LIKE ? OR code LIKE ? OR description LIKE ?", pattern, pattern, pattern)

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 获取列表
	if err := query.Offset(offset).Limit(limit).Find(&permissions).Error; err != nil {
		return nil, 0, err
	}

	return permissions, total, nil
}

// ListByParentID 根据父ID获取权限列表
func (r *PermissionRepository) ListByParentID(ctx context.Context, parentID int64) ([]*domain.Permission, error) {
	var permissions []*domain.Permission
	err := r.db.WithContext(ctx).Where("parent_id = ?", parentID).Find(&permissions).Error
	if err != nil {
		return nil, err
	}
	return permissions, nil
}

// GetByIDs 根据ID列表批量获取权限
func (r *PermissionRepository) GetByIDs(ctx context.Context, ids []int64) ([]*domain.Permission, error) {
	if len(ids) == 0 {
		return []*domain.Permission{}, nil
	}

	var permissions []*domain.Permission
	err := r.db.WithContext(ctx).Where("id IN ?", ids).Find(&permissions).Error
	if err != nil {
		return nil, err
	}
	return permissions, nil
}
