import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

import 'supabase_provider.dart';
import '../utils/app_time.dart';

/// Admin user query parameters for server-side pagination.
class AdminUserQuery {
  /// Creates admin user query parameters.
  const AdminUserQuery({
    this.offset = 0,
    this.limit = 50,
    this.searchQuery = '',
  });

  /// Offset for pagination.
  final int offset;

  /// Number of items per page (default: 50).
  final int limit;

  /// Full text search query.
  final String searchQuery;

  AdminUserQuery copyWith({int? offset, int? limit, String? searchQuery}) {
    return AdminUserQuery(
      offset: offset ?? this.offset,
      limit: limit ?? this.limit,
      searchQuery: searchQuery ?? this.searchQuery,
    );
  }
}

final adminUserQueryProvider = StateProvider<AdminUserQuery>(
  (ref) => const AdminUserQuery(),
);

final adminUserControllerProvider = Provider<AdminUserController>((ref) {
  final client = ref.watch(supabaseClientProvider);
  return AdminUserController(client);
});

class AdminUserStatus {
  AdminUserStatus({required this.email, required this.bannedUntil});

  final String? email;
  final DateTime? bannedUntil;

  bool get isLocked {
    if (bannedUntil == null) return false;
    return bannedUntil!.isAfter(AppTime.now());
  }
}

class AdminUserController {
  AdminUserController(this._client);

  final SupabaseClient _client;

  Future<void> updateProfile({
    required String userId,
    required String fullName,
    required String role,
  }) async {
    await _client
        .from('profiles')
        .update({'full_name': fullName, 'role': role})
        .eq('id', userId);
  }

  Future<void> updateRole({
    required String userId,
    required String role,
  }) async {
    await _client.from('profiles').update({'role': role}).eq('id', userId);
  }

  // Centralized helper that calls the admin Edge Function and surfaces
  // a clear error for 401/bad_jwt so the UI can react (sign out/reauth).
  Future<dynamic> _invokeAdminFunction(
    String action,
    Map<String, dynamic> payload,
  ) async {
    final accessToken = _client.auth.currentSession?.accessToken;
    final response = await _client.functions.invoke(
      'admin_user_management',
      body: {'action': action, ...payload},
      headers: accessToken == null
          ? null
          : {'Authorization': 'Bearer $accessToken'},
    );

    if (response.status == 401) {
      // If the gateway rejects the JWT, proactively clear the local session
      // so the app can re-authenticate and obtain a valid Supabase token.
      try {
        await _client.auth.signOut();
      } catch (_) {
        // ignore sign-out errors
      }
      throw Exception(
        'Unauthorized: invalid or expired session token (bad_jwt)',
      );
    }

    if (response.status != 200) {
      throw Exception(response.data ?? 'Admin request failed');
    }

    return response.data;
  }

  Future<void> setPassword({
    required String userId,
    required String password,
  }) async {
    if (password.length < 8) {
      throw Exception('Password must be at least 8 characters');
    }

    await _invokeAdminFunction('set_password', {
      'userId': userId,
      'password': password,
    });
  }

  Future<void> setLock({required String userId, required bool locked}) async {
    await _invokeAdminFunction('set_lock', {
      'userId': userId,
      'locked': locked,
    });
  }

  Future<AdminUserStatus> fetchStatus(String userId) async {
    final data = await _invokeAdminFunction('get_user', {'userId': userId});
    final user =
        (data as Map<String, dynamic>?)?['user'] as Map<String, dynamic>?;
    final email = user?['email'] as String?;
    DateTime? bannedUntil;
    final bannedRaw = user?['banned_until'];
    if (bannedRaw is String) {
      bannedUntil = DateTime.tryParse(bannedRaw);
    } else if (bannedRaw is DateTime) {
      bannedUntil = bannedRaw;
    }
    return AdminUserStatus(
      email: email,
      bannedUntil: bannedUntil == null ? null : AppTime.toAppTime(bannedUntil),
    );
  }

  Future<List<Map<String, dynamic>>> listUsers(AdminUserQuery q) async {
    final data = await _invokeAdminFunction('list_users', {
      'offset': q.offset,
      'limit': q.limit,
      'searchQuery': q.searchQuery,
    });

    final users = (data is Map && data['users'] is List)
        ? (data['users'] as List).cast<Map<String, dynamic>>()
        : <Map<String, dynamic>>[];
    return users;
  }
}

final adminUserStatusProvider = FutureProvider.family
    .autoDispose<AdminUserStatus, String>((ref, userId) {
      return ref.watch(adminUserControllerProvider).fetchStatus(userId);
    });

final adminUsersProvider =
    FutureProvider.autoDispose<List<Map<String, dynamic>>>((ref) {
      final q = ref.watch(adminUserQueryProvider);
      final ctrl = ref.watch(adminUserControllerProvider);
      return ctrl.listUsers(q);
    });
