import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../models/office.dart';
import '../../models/profile.dart';
import '../../models/ticket_message.dart';
import '../../models/user_office.dart';
import '../../providers/admin_user_provider.dart';
import '../../providers/auth_provider.dart';
import '../../providers/profile_provider.dart';
import '../../providers/tickets_provider.dart';
import '../../theme/app_surfaces.dart';
import '../../providers/user_offices_provider.dart';

import '../../utils/app_time.dart';
import '../../widgets/mono_text.dart';
import '../../widgets/responsive_body.dart';
import '../../widgets/tasq_adaptive_list.dart';
import '../../utils/snackbar.dart';

class UserManagementScreen extends ConsumerStatefulWidget {
  const UserManagementScreen({super.key});

  @override
  ConsumerState<UserManagementScreen> createState() =>
      _UserManagementScreenState();
}

class _UserManagementScreenState extends ConsumerState<UserManagementScreen> {
  static const List<String> _roles = [
    'standard',
    'dispatcher',
    'it_staff',
    'admin',
  ];

  final _fullNameController = TextEditingController();
  final _searchController = TextEditingController();

  String? _selectedUserId;
  String? _selectedRole;
  final Set<String> _selectedOfficeIds = {};
  bool _isSaving = false;

  @override
  void dispose() {
    _fullNameController.dispose();
    _searchController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final isAdmin = ref.watch(isAdminProvider);
    final profilesAsync = ref.watch(profilesProvider);
    final officesAsync = ref.watch(officesProvider);
    final assignmentsAsync = ref.watch(userOfficesProvider);
    final messagesAsync = ref.watch(ticketMessagesAllProvider);

    return ResponsiveBody(
      maxWidth: double.infinity,
      child: !isAdmin
          ? const Center(child: Text('Admin access required.'))
          : _buildContent(
              context,
              profilesAsync,
              officesAsync,
              assignmentsAsync,
              messagesAsync,
            ),
    );
  }

  Widget _buildContent(
    BuildContext context,
    AsyncValue<List<Profile>> profilesAsync,
    AsyncValue<List<Office>> officesAsync,
    AsyncValue<List<UserOffice>> assignmentsAsync,
    AsyncValue<List<TicketMessage>> messagesAsync,
  ) {
    if (profilesAsync.isLoading ||
        officesAsync.isLoading ||
        assignmentsAsync.isLoading ||
        messagesAsync.isLoading) {
      return const Center(child: CircularProgressIndicator());
    }

    if (profilesAsync.hasError ||
        officesAsync.hasError ||
        assignmentsAsync.hasError ||
        messagesAsync.hasError) {
      final error =
          profilesAsync.error ??
          officesAsync.error ??
          assignmentsAsync.error ??
          messagesAsync.error ??
          'Unknown error';
      return Center(child: Text('Failed to load data: $error'));
    }

    final profiles = profilesAsync.valueOrNull ?? [];
    final offices = officesAsync.valueOrNull ?? [];
    final assignments = assignmentsAsync.valueOrNull ?? [];
    final messages = messagesAsync.valueOrNull ?? [];

    final lastActiveByUser = <String, DateTime>{};
    for (final message in messages) {
      final senderId = message.senderId;
      if (senderId == null) continue;
      final current = lastActiveByUser[senderId];
      if (current == null || message.createdAt.isAfter(current)) {
        lastActiveByUser[senderId] = message.createdAt;
      }
    }

    if (profiles.isEmpty) {
      return const Center(child: Text('No users found.'));
    }

    final query = _searchController.text.trim().toLowerCase();
    final filteredProfiles = query.isEmpty
        ? profiles
        : profiles.where((profile) {
            final label = profile.fullName.isNotEmpty
                ? profile.fullName
                : profile.id;
            return label.toLowerCase().contains(query) ||
                profile.id.toLowerCase().contains(query);
          }).toList();

    final officeCountByUser = <String, int>{};
    for (final assignment in assignments) {
      officeCountByUser.update(
        assignment.userId,
        (value) => value + 1,
        ifAbsent: () => 1,
      );
    }

    final listBody = TasQAdaptiveList<Profile>(
      items: filteredProfiles,
      filterHeader: SizedBox(
        width: 320,
        child: TextField(
          controller: _searchController,
          onChanged: (_) => setState(() {}),
          decoration: const InputDecoration(
            labelText: 'Search name',
            prefixIcon: Icon(Icons.search),
          ),
        ),
      ),
      columns: [
        TasQColumn<Profile>(
          header: 'User',
          cellBuilder: (context, profile) {
            final label = profile.fullName.isEmpty
                ? profile.id
                : profile.fullName;
            return Text(label);
          },
        ),
        TasQColumn<Profile>(
          header: 'Email',
          cellBuilder: (context, profile) {
            final statusAsync = ref.watch(adminUserStatusProvider(profile.id));
            return statusAsync.when(
              data: (s) => Text(s.email ?? 'Unknown'),
              loading: () => const Text('Loading...'),
              error: (error, stack) => const Text('Unknown'),
            );
          },
        ),
        TasQColumn<Profile>(
          header: 'Role',
          cellBuilder: (context, profile) => Text(profile.role),
        ),
        TasQColumn<Profile>(
          header: 'Offices',
          cellBuilder: (context, profile) {
            final officesAssigned = officeCountByUser[profile.id] ?? 0;
            return Text(officesAssigned == 0 ? 'None' : '$officesAssigned');
          },
        ),
        TasQColumn<Profile>(
          header: 'Status',
          cellBuilder: (context, profile) {
            final statusAsync = ref.watch(adminUserStatusProvider(profile.id));
            return statusAsync.when(
              data: (s) {
                final statusLabel = s.isLocked ? 'Locked' : 'Active';
                return _StatusBadge(label: statusLabel);
              },
              loading: () => _StatusBadge(label: 'Loading'),
              error: (error, stack) => _StatusBadge(label: 'Unknown'),
            );
          },
        ),
        TasQColumn<Profile>(
          header: 'Last active',
          cellBuilder: (context, profile) {
            final lastActive = lastActiveByUser[profile.id];
            return Text(_formatLastActiveLabel(lastActive));
          },
        ),
      ],
      onRowTap: (profile) =>
          _showUserDialog(context, profile, offices, assignments),
      mobileTileBuilder: (context, profile, actions) {
        final label = profile.fullName.isEmpty ? profile.id : profile.fullName;
        final statusAsync = ref.watch(adminUserStatusProvider(profile.id));
        final officesAssigned = officeCountByUser[profile.id] ?? 0;
        final lastActive = lastActiveByUser[profile.id];

        return Card(
          child: ListTile(
            dense: true,
            visualDensity: VisualDensity.compact,
            title: Text(label),
            subtitle: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const SizedBox(height: 2),
                Text('Role: ${profile.role}'),
                Text('Offices: $officesAssigned'),
                Text('Last active: ${_formatLastActiveLabel(lastActive)}'),
                const SizedBox(height: 4),
                MonoText('ID ${profile.id}'),
                statusAsync.when(
                  data: (s) => Text('Email: ${s.email ?? 'Unknown'}'),
                  loading: () => const Text('Email: Loading...'),
                  error: (error, stack) => const Text('Email: Unknown'),
                ),
              ],
            ),
            trailing: statusAsync.when(
              data: (s) =>
                  _StatusBadge(label: s.isLocked ? 'Locked' : 'Active'),
              loading: () => _StatusBadge(label: 'Loading'),
              error: (error, stack) => _StatusBadge(label: 'Unknown'),
            ),
            onTap: () =>
                _showUserDialog(context, profile, offices, assignments),
          ),
        );
      },
      onRequestRefresh: () {
        // For server-side pagination, update the query provider
        ref.read(adminUserQueryProvider.notifier).state = const AdminUserQuery(
          offset: 0,
          limit: 50,
        );
      },
      onPageChanged: (firstRow) {
        ref
            .read(adminUserQueryProvider.notifier)
            .update((q) => q.copyWith(offset: firstRow));
      },
      isLoading: false,
    );

    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 16),
      child: Column(
        mainAxisSize: MainAxisSize.max,
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Align(
            alignment: Alignment.center,
            child: Text(
              'User Management',
              textAlign: TextAlign.center,
              style: Theme.of(
                context,
              ).textTheme.titleLarge?.copyWith(fontWeight: FontWeight.w700),
            ),
          ),
          const SizedBox(height: 16),
          Expanded(child: listBody),
        ],
      ),
    );
  }

  Future<void> _showUserDialog(
    BuildContext context,
    Profile profile,
    List<Office> offices,
    List<UserOffice> assignments,
  ) async {
    final currentOfficeIds = assignments
        .where((assignment) => assignment.userId == profile.id)
        .map((assignment) => assignment.officeId)
        .toSet();

    // Populate dialog-backed state so form fields reflect the selected user.
    if (mounted) {
      setState(() {
        _selectedUserId = profile.id;
        _selectedRole = profile.role;
        _fullNameController.text = profile.fullName;
        _selectedOfficeIds
          ..clear()
          ..addAll(currentOfficeIds);
      });
    }

    if (!context.mounted) return;
    await showDialog<void>(
      context: context,
      builder: (dialogContext) {
        return StatefulBuilder(
          builder: (context, setDialogState) {
            return AlertDialog(
              shape: AppSurfaces.of(context).dialogShape,
              title: const Text('Update user'),
              content: ConstrainedBox(
                constraints: const BoxConstraints(maxWidth: 520),
                child: SingleChildScrollView(
                  child: _buildUserForm(
                    context,
                    profile,
                    offices,
                    currentOfficeIds,
                    setDialogState,
                  ),
                ),
              ),
              actions: [
                TextButton(
                  onPressed: () => Navigator.of(dialogContext).pop(),
                  child: const Text('Close'),
                ),
              ],
            );
          },
        );
      },
    );

    // Clear the temporary selection state after the dialog is closed so the
    // next dialog starts from a clean slate.
    if (mounted) {
      setState(() {
        _selectedUserId = null;
        _selectedRole = null;
        _selectedOfficeIds.clear();
        _fullNameController.clear();
      });
    }
  }

  Widget _buildUserForm(
    BuildContext context,
    Profile profile,
    List<Office> offices,
    Set<String> currentOfficeIds,
    StateSetter setDialogState,
  ) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        TextFormField(
          controller: _fullNameController,
          decoration: const InputDecoration(labelText: 'Full name'),
        ),
        const SizedBox(height: 12),
        DropdownButtonFormField<String>(
          key: ValueKey('role_${_selectedUserId ?? 'none'}'),
          initialValue: _selectedRole,
          items: _roles
              .map((role) => DropdownMenuItem(value: role, child: Text(role)))
              .toList(),
          onChanged: (value) => setDialogState(() => _selectedRole = value),
          decoration: const InputDecoration(labelText: 'Role'),
        ),
        const SizedBox(height: 12),

        // Email and lock status are retrieved from auth via Edge Function / admin API.
        Consumer(
          builder: (context, ref, _) {
            final statusAsync = ref.watch(adminUserStatusProvider(profile.id));
            return Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                statusAsync.when(
                  data: (s) => Text(
                    'Email: ${s.email ?? 'Unknown'}',
                    style: Theme.of(context).textTheme.bodySmall,
                  ),
                  loading: () => Text(
                    'Email: Loading...',
                    style: Theme.of(context).textTheme.bodySmall,
                  ),
                  error: (error, stack) => Text(
                    'Email: Unknown',
                    style: Theme.of(context).textTheme.bodySmall,
                  ),
                ),
                const SizedBox(height: 8),
                Row(
                  children: [
                    OutlinedButton.icon(
                      onPressed: _isSaving
                          ? null
                          : () => _showPasswordResetDialog(profile.id),
                      icon: const Icon(Icons.password),
                      label: const Text('Reset password'),
                    ),
                    const SizedBox(width: 12),
                    statusAsync.when(
                      data: (s) => OutlinedButton.icon(
                        onPressed: _isSaving
                            ? null
                            : () => _toggleLock(profile.id, !s.isLocked),
                        icon: Icon(s.isLocked ? Icons.lock_open : Icons.lock),
                        label: Text(s.isLocked ? 'Unlock' : 'Lock'),
                      ),
                      loading: () => OutlinedButton.icon(
                        onPressed: null,
                        icon: const Icon(Icons.lock),
                        label: const Text('Loading...'),
                      ),
                      error: (error, stack) => OutlinedButton.icon(
                        onPressed: _isSaving
                            ? null
                            : () => _toggleLock(profile.id, true),
                        icon: const Icon(Icons.lock),
                        label: const Text('Lock'),
                      ),
                    ),
                  ],
                ),
              ],
            );
          },
        ),

        const SizedBox(height: 16),
        Text('Offices', style: Theme.of(context).textTheme.titleSmall),
        const SizedBox(height: 8),
        if (offices.isEmpty) const Text('No offices available.'),
        if (offices.isNotEmpty)
          Column(
            children: offices
                .map(
                  (office) => CheckboxListTile(
                    value: _selectedOfficeIds.contains(office.id),
                    onChanged: _isSaving
                        ? null
                        : (selected) {
                            setDialogState(() {
                              if (selected == true) {
                                _selectedOfficeIds.add(office.id);
                              } else {
                                _selectedOfficeIds.remove(office.id);
                              }
                            });
                          },
                    title: Text(office.name),
                    controlAffinity: ListTileControlAffinity.leading,
                    contentPadding: EdgeInsets.zero,
                  ),
                )
                .toList(),
          ),
        const SizedBox(height: 16),
        Row(
          children: [
            Expanded(
              child: FilledButton(
                onPressed: _isSaving
                    ? null
                    : () async {
                        final saved = await _saveChanges(
                          context,
                          profile,
                          currentOfficeIds,
                          setDialogState,
                        );
                        if (saved && context.mounted) {
                          Navigator.of(context).pop();
                        }
                      },
                child: _isSaving
                    ? const SizedBox(
                        height: 18,
                        width: 18,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const Text('Save changes'),
              ),
            ),
          ],
        ),
      ],
    );
  }

  Future<bool> _saveChanges(
    BuildContext context,
    Profile profile,
    Set<String> currentOfficeIds,
    StateSetter setDialogState,
  ) async {
    final role = _selectedRole ?? profile.role;
    final fullName = _fullNameController.text.trim();
    if (fullName.isEmpty) {
      showWarningSnackBar(context, 'Full name is required.');
      return false;
    }

    if (_selectedOfficeIds.isEmpty) {
      showWarningSnackBar(context, 'Select at least one office.');
      return false;
    }

    setDialogState(() => _isSaving = true);
    try {
      await ref
          .read(adminUserControllerProvider)
          .updateProfile(userId: profile.id, fullName: fullName, role: role);

      final toAdd = _selectedOfficeIds.difference(currentOfficeIds);
      final toRemove = currentOfficeIds.difference(_selectedOfficeIds);
      final controller = ref.read(userOfficesControllerProvider);

      for (final officeId in toAdd) {
        await controller.assignUserOffice(
          userId: profile.id,
          officeId: officeId,
        );
      }

      for (final officeId in toRemove) {
        await controller.removeUserOffice(
          userId: profile.id,
          officeId: officeId,
        );
      }

      ref.invalidate(profilesProvider);
      ref.invalidate(userOfficesProvider);

      if (!context.mounted) return true;
      showSuccessSnackBar(context, 'User "$fullName" updated successfully.');
      return true;
    } catch (error) {
      if (!context.mounted) return false;
      showErrorSnackBar(context, 'Update failed: $error');
      return false;
    } finally {
      setDialogState(() => _isSaving = false);
    }
  }

  Future<void> _showPasswordResetDialog(String userId) async {
    final controller = TextEditingController();
    final formKey = GlobalKey<FormState>();

    await showDialog<void>(
      context: context,
      builder: (dialogContext) {
        return AlertDialog(
          title: const Text('Set temporary password'),
          content: Form(
            key: formKey,
            child: TextFormField(
              controller: controller,
              decoration: const InputDecoration(labelText: 'New password'),
              obscureText: true,
              validator: (value) {
                if (value == null || value.trim().length < 8) {
                  return 'Use at least 8 characters.';
                }
                return null;
              },
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(dialogContext).pop(),
              child: const Text('Cancel'),
            ),
            FilledButton(
              onPressed: () async {
                if (!formKey.currentState!.validate()) return;
                try {
                  await ref
                      .read(adminUserControllerProvider)
                      .setPassword(
                        userId: userId,
                        password: controller.text.trim(),
                      );
                  if (!dialogContext.mounted) return;
                  Navigator.of(dialogContext).pop();
                  if (!mounted) return;
                  showSuccessSnackBar(context, 'Password updated.');
                } catch (error) {
                  final msg = error.toString();
                  if (msg.contains('Unauthorized') ||
                      msg.contains('bad_jwt') ||
                      msg.contains('expired')) {
                    await ref.read(authControllerProvider).signOut();
                    if (!mounted) return;
                    showInfoSnackBar(
                      context,
                      'Session expired — please sign in again.',
                    );
                    return;
                  }

                  if (!mounted) return;
                  showErrorSnackBar(context, 'Reset failed: $error');
                }
              },
              child: const Text('Update password'),
            ),
          ],
        );
      },
    );
  }

  Future<void> _toggleLock(String userId, bool locked) async {
    setState(() => _isSaving = true);
    try {
      // Use AdminUserController (Edge Function or direct DB) to lock/unlock.
      await ref
          .read(adminUserControllerProvider)
          .setLock(userId: userId, locked: locked);

      // Refresh profile streams so other UI updates observe the change.
      ref.invalidate(profilesProvider);
      ref.invalidate(currentProfileProvider);

      if (!mounted) return;
      showInfoSnackBar(
        context,
        locked ? 'User locked (app-level).' : 'User unlocked (app-level).',
      );
    } catch (error) {
      final msg = error.toString();
      if (msg.contains('Unauthorized') ||
          msg.contains('bad_jwt') ||
          msg.contains('expired')) {
        await ref.read(authControllerProvider).signOut();
        if (!mounted) return;
        showInfoSnackBar(context, 'Session expired — please sign in again.');
        return;
      }

      if (!mounted) return;
      showErrorSnackBar(context, 'Lock update failed: $error');
    } finally {
      if (mounted) {
        setState(() => _isSaving = false);
      }
    }
  }
}

String _formatLastActiveLabel(DateTime? value) {
  if (value == null) return 'N/A';
  final now = AppTime.now();
  final diff = now.difference(value);
  if (diff.inMinutes < 1) return 'Just now';
  if (diff.inHours < 1) return '${diff.inMinutes}m ago';
  if (diff.inDays < 1) return '${diff.inHours}h ago';
  if (diff.inDays < 7) return '${diff.inDays}d ago';
  final month = value.month.toString().padLeft(2, '0');
  final day = value.day.toString().padLeft(2, '0');
  return '${value.year}-$month-$day';
}

class _StatusBadge extends StatelessWidget {
  const _StatusBadge({required this.label});

  final String label;

  @override
  Widget build(BuildContext context) {
    final scheme = Theme.of(context).colorScheme;
    final isError = label.toLowerCase().contains('error');
    final background = isError
        ? scheme.errorContainer
        : scheme.secondaryContainer;
    final foreground = isError
        ? scheme.onErrorContainer
        : scheme.onSecondaryContainer;

    return Badge(
      backgroundColor: background,
      label: Text(
        label,
        style: Theme.of(context).textTheme.labelSmall?.copyWith(
          color: foreground,
          fontWeight: FontWeight.w600,
          letterSpacing: 0.3,
        ),
      ),
    );
  }
}
