import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../core/network/api_client.dart'; import '../../../core/network/signalr_service.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/widgets/glass_container.dart'; import '../models/admin_update_user_request_dto.dart'; import '../models/admin_user_model.dart'; import '../bloc/admin_bloc.dart'; import '../repositories/admin_repository.dart'; import '../widgets/admin_kpi_header.dart'; import '../widgets/admin_user_card_item.dart'; import '../widgets/create_user_dialog.dart'; import '../widgets/edit_user_dialog.dart'; import '../widgets/system_diagnostics_widget.dart'; class AdminUsersScreen extends StatelessWidget { final ApiClient apiClient; final SignalRService? signalRService; const AdminUsersScreen({ super.key, required this.apiClient, this.signalRService, }); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => AdminBloc( repository: AdminRepository(apiClient: apiClient), )..add(FetchAdminUsers()), child: _AdminUsersScreenContent( apiClient: apiClient, signalRService: signalRService, ), ); } } class _AdminUsersScreenContent extends StatefulWidget { final ApiClient apiClient; final SignalRService? signalRService; const _AdminUsersScreenContent({ required this.apiClient, this.signalRService, }); @override State<_AdminUsersScreenContent> createState() => _AdminUsersScreenContentState(); } class _AdminUsersScreenContentState extends State<_AdminUsersScreenContent> with SingleTickerProviderStateMixin { late TabController _tabController; String _searchQuery = ''; String _roleFilter = 'Alle'; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); } @override void dispose() { _tabController.dispose(); super.dispose(); } void _openCreateUser(BuildContext context) async { final res = await showDialog(context: context, builder: (_) => const CreateUserDialog()); if (res != null && context.mounted) { context.read().add(CreateAdminUser(res)); } } void _openEditUser(BuildContext context, AdminUserModel user) async { final res = await showDialog(context: context, builder: (_) => EditUserDialog(user: user)); if (res != null && context.mounted) { context.read().add(UpdateAdminUser(user.id, res as AdminUpdateUserRequestDto)); } } void _toggleUserActiveStatus(BuildContext context, AdminUserModel user, bool newActive) { final dto = AdminUpdateUserRequestDto(role: user.role, isActive: newActive); context.read().add(UpdateAdminUser(user.id, dto)); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.transparent, body: BlocBuilder( builder: (context, state) { final users = state is AdminLoaded ? state.users : []; return Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Administration & System', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white), ), const SizedBox(height: 2), Text( 'Finlytic Admin-Dashboard • Microservices & Benutzer', style: TextStyle(color: AppTheme.textMuted, fontSize: 13), ), ], ), Row( children: [ IconButton( onPressed: () => context.read().add(FetchAdminUsers()), icon: const Icon(Icons.refresh_rounded, color: Colors.white70), tooltip: 'Neu laden', ), const SizedBox(width: 8), ElevatedButton.icon( onPressed: () => _openCreateUser(context), icon: const Icon(Icons.person_add_alt_1_rounded, size: 18), label: const Text('Neuer Benutzer'), style: ElevatedButton.styleFrom( backgroundColor: AppTheme.primaryEmerald, foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ), ], ), ], ), const SizedBox(height: 16), AdminKpiHeader( users: users, signalRService: widget.signalRService, ), const SizedBox(height: 16), Container( decoration: BoxDecoration( color: AppTheme.glassSurface, borderRadius: BorderRadius.circular(14), border: Border.all(color: AppTheme.glassBorder), ), child: TabBar( controller: _tabController, indicatorColor: AppTheme.primaryEmerald, indicatorSize: TabBarIndicatorSize.tab, labelColor: AppTheme.primaryEmerald, unselectedLabelColor: AppTheme.textMuted, labelStyle: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), indicator: BoxDecoration( color: AppTheme.primaryEmerald.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(12), border: Border.all(color: AppTheme.primaryEmerald.withValues(alpha: 0.4)), ), tabs: const [ Tab(icon: Icon(Icons.people_alt_outlined, size: 18), text: 'Nutzerverwaltung'), Tab(icon: Icon(Icons.monitor_heart_outlined, size: 18), text: 'System-Diagnose & MQTT'), ], ), ), const SizedBox(height: 16), Expanded( child: TabBarView( controller: _tabController, children: [ _buildUserManagementTab(context, state, users), SystemDiagnosticsWidget(signalRService: widget.signalRService), ], ), ), ], ), ); }, ), ); } Widget _buildUserManagementTab(BuildContext context, AdminState state, List allUsers) { if (state is AdminLoading) { return Center(child: CircularProgressIndicator(color: AppTheme.primaryEmerald)); } if (state is AdminError) { return Center( child: GlassContainer( padding: const EdgeInsets.all(24), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.error_outline_rounded, color: AppTheme.accentRed, size: 40), const SizedBox(height: 12), Text(state.message, style: TextStyle(color: AppTheme.textPrimary, fontWeight: FontWeight.bold)), const SizedBox(height: 16), ElevatedButton( onPressed: () => context.read().add(FetchAdminUsers()), style: ElevatedButton.styleFrom(backgroundColor: AppTheme.primaryEmerald, foregroundColor: Colors.black), child: const Text('Erneut versuchen'), ), ], ), ), ); } final filteredUsers = allUsers.where((u) { final matchesSearch = u.fullName.toLowerCase().contains(_searchQuery.toLowerCase()) || u.email.toLowerCase().contains(_searchQuery.toLowerCase()); final matchesRole = _roleFilter == 'Alle' || u.role.toLowerCase() == _roleFilter.toLowerCase(); return matchesSearch && matchesRole; }).toList(); return Column( children: [ Row( children: [ Expanded( child: TextField( onChanged: (val) => setState(() => _searchQuery = val), decoration: InputDecoration( hintText: 'Benutzer nach Name oder E-Mail suchen...', prefixIcon: Icon(Icons.search_rounded, color: AppTheme.textMuted), suffixIcon: _searchQuery.isNotEmpty ? IconButton( icon: const Icon(Icons.clear, size: 18), onPressed: () => setState(() => _searchQuery = ''), ) : null, ), ), ), const SizedBox(width: 12), SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: ['Alle', 'Admin', 'Premium', 'User'].map((role) { final isSelected = _roleFilter == role; return Padding( padding: const EdgeInsets.only(right: 6), child: ChoiceChip( label: Text(role), selected: isSelected, selectedColor: AppTheme.primaryEmerald, backgroundColor: AppTheme.glassSurface, labelStyle: TextStyle( color: isSelected ? Colors.black : AppTheme.textSecondary, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, fontSize: 12, ), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), side: BorderSide(color: isSelected ? AppTheme.primaryEmerald : AppTheme.glassBorder), onSelected: (val) { if (val) setState(() => _roleFilter = role); }, ), ); }).toList(), ), ), ], ), const SizedBox(height: 14), Expanded( child: filteredUsers.isEmpty ? Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.person_search_outlined, size: 48, color: AppTheme.textMuted), const SizedBox(height: 12), Text('Keine passenden Benutzer gefunden.', style: TextStyle(color: AppTheme.textMuted, fontSize: 14)), ], ), ) : ListView.builder( itemCount: filteredUsers.length, itemBuilder: (context, index) { final u = filteredUsers[index]; return AdminUserCardItem( user: u, onToggleActive: (val) => _toggleUserActiveStatus(context, u, val), onEdit: () => _openEditUser(context, u), ); }, ), ), ], ); } }