package repository

import (
	"context"

	"gorm.io/gorm"

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

// UserRoleRepository 用户角色关联数据访问层
type UserRoleRepository struct {
	db *gorm.DB
}

// NewUserRoleRepository 创建用户角色关联数据访问层
func NewUserRoleRepository(db *gorm.DB) *UserRoleRepository {
	return &UserRoleRepository{db: db}
}

// DB returns the underlying GORM DB for transaction support
func (r *UserRoleRepository) DB() *gorm.DB {
	return r.db
}

// WithTx returns a new repository instance that uses the given transaction
func (r *UserRoleRepository) WithTx(tx *gorm.DB) *UserRoleRepository {
	return &UserRoleRepository{db: tx}
}

// Create 创建用户角色关联
func (r *UserRoleRepository) Create(ctx context.Context, userRole *domain.UserRole) error {
	return r.db.WithContext(ctx).Create(userRole).Error
}

// Delete 删除用户角色关联
func (r *UserRoleRepository) Delete(ctx context.Context, id int64) error {
	return r.db.WithContext(ctx).Delete(&domain.UserRole{}, id).Error
}

// DeleteByUserID 删除用户的所有角色
func (r *UserRoleRepository) DeleteByUserID(ctx context.Context, userID int64) error {
	return r.db.WithContext(ctx).Where("user_id = ?", userID).Delete(&domain.UserRole{}).Error
}

// DeleteByUserAndRole 删除指定用户和角色的关联
func (r *UserRoleRepository) DeleteByUserAndRole(ctx context.Context, userID, roleID int64) error {
	return r.db.WithContext(ctx).Where("user_id = ? AND role_id = ?", userID, roleID).Delete(&domain.UserRole{}).Error
}

// DeleteByRoleID 删除角色的所有用户
func (r *UserRoleRepository) DeleteByRoleID(ctx context.Context, roleID int64) error {
	return r.db.WithContext(ctx).Where("role_id = ?", roleID).Delete(&domain.UserRole{}).Error
}

// GetByUserID 根据用户ID获取角色列表
func (r *UserRoleRepository) GetByUserID(ctx context.Context, userID int64) ([]*domain.UserRole, error) {
	var userRoles []*domain.UserRole
	err := r.db.WithContext(ctx).Where("user_id = ?", userID).Find(&userRoles).Error
	if err != nil {
		return nil, err
	}
	return userRoles, nil
}

// GetByRoleID 根据角色ID获取用户列表
func (r *UserRoleRepository) GetByRoleID(ctx context.Context, roleID int64) ([]*domain.UserRole, error) {
	var userRoles []*domain.UserRole
	err := r.db.WithContext(ctx).Where("role_id = ?", roleID).Find(&userRoles).Error
	if err != nil {
		return nil, err
	}
	return userRoles, nil
}

// GetRoleIDsByUserID 根据用户ID获取角色ID列表
func (r *UserRoleRepository) GetRoleIDsByUserID(ctx context.Context, userID int64) ([]int64, error) {
	var roleIDs []int64
	err := r.db.WithContext(ctx).Model(&domain.UserRole{}).Where("user_id = ?", userID).Pluck("role_id", &roleIDs).Error
	if err != nil {
		return nil, err
	}
	return roleIDs, nil
}

// GetUserRolesAndPermissions 获取用户角色和权限（PERF-01 优化：合并为单次 JOIN 查询）
func (r *UserRoleRepository) GetUserRolesAndPermissions(ctx context.Context, userID int64) ([]*domain.Role, []*domain.Permission, error) {
	var results []struct {
		RoleID       int64
		RoleName     string
		RoleCode     string
		RoleStatus   int
		PermissionID int64
		PermissionCode string
		PermissionName string
	}

	// 使用 LEFT JOIN 一次性获取用户角色和权限
	err := r.db.WithContext(ctx).
		Raw(`
			SELECT DISTINCT r.id as role_id, r.name as role_name, r.code as role_code, r.status as role_status,
			       p.id as permission_id, p.code as permission_code, p.name as permission_name
			FROM user_roles ur
			JOIN roles r ON ur.role_id = r.id
			LEFT JOIN role_permissions rp ON r.id = rp.role_id
			LEFT JOIN permissions p ON rp.permission_id = p.id
			WHERE ur.user_id = ? AND r.status = 1
		`, userID).
		Scan(&results).Error
	if err != nil {
		return nil, nil, err
	}

	// 构建角色和权限列表
	roleMap := make(map[int64]*domain.Role)
	permMap := make(map[int64]*domain.Permission)

	for _, row := range results {
		if _, ok := roleMap[row.RoleID]; !ok {
			roleMap[row.RoleID] = &domain.Role{
				ID:   row.RoleID,
				Name: row.RoleName,
				Code: row.RoleCode,
				Status: domain.RoleStatus(row.RoleStatus),
			}
		}
		if row.PermissionID > 0 {
			if _, ok := permMap[row.PermissionID]; !ok {
				permMap[row.PermissionID] = &domain.Permission{
					ID:   row.PermissionID,
					Code: row.PermissionCode,
					Name: row.PermissionName,
				}
			}
		}
	}

	roles := make([]*domain.Role, 0, len(roleMap))
	for _, role := range roleMap {
		roles = append(roles, role)
	}

	perms := make([]*domain.Permission, 0, len(permMap))
	for _, perm := range permMap {
		perms = append(perms, perm)
	}

	return roles, perms, nil
}

// GetUserIDByRoleID 根据角色ID获取用户ID列表
func (r *UserRoleRepository) GetUserIDByRoleID(ctx context.Context, roleID int64) ([]int64, error) {
	var userIDs []int64
	err := r.db.WithContext(ctx).Model(&domain.UserRole{}).Where("role_id = ?", roleID).Pluck("user_id", &userIDs).Error
	if err != nil {
		return nil, err
	}
	return userIDs, nil
}

// Exists 检查用户角色关联是否存在
func (r *UserRoleRepository) Exists(ctx context.Context, userID, roleID int64) (bool, error) {
	var count int64
	err := r.db.WithContext(ctx).Model(&domain.UserRole{}).
		Where("user_id = ? AND role_id = ?", userID, roleID).
		Count(&count).Error
	return count > 0, err
}

// BatchCreate 批量创建用户角色关联
func (r *UserRoleRepository) BatchCreate(ctx context.Context, userRoles []*domain.UserRole) error {
	if len(userRoles) == 0 {
		return nil
	}
	return r.db.WithContext(ctx).Create(&userRoles).Error
}

// BatchDelete 批量删除用户角色关联
func (r *UserRoleRepository) BatchDelete(ctx context.Context, userRoles []*domain.UserRole) error {
	if len(userRoles) == 0 {
		return nil
	}
	
	var ids []int64
	for _, ur := range userRoles {
		ids = append(ids, ur.ID)
	}
	
	return r.db.WithContext(ctx).Delete(&domain.UserRole{}, ids).Error
}
