import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../../core/api/api_client.dart';
import '../../../core/api/api_paths.dart';
import '../../../core/api/guarded_api_call.dart';
import '../../auth/data/auth_providers.dart';
import '../domain/admin_ai_categorize_result.dart';
import '../domain/admin_category_node.dart';
import '../domain/admin_product.dart';
import '../domain/ai_model_info.dart';
import '../domain/pending_product.dart';
import '../domain/user_admin.dart';

final adminRepositoryProvider = Provider<AdminRepository>((ref) {
  return AdminRepository(ref.watch(apiClientProvider), ref);
});

class AdminRepository {
  final ApiClient _apiClient;
  final Ref _ref;

  AdminRepository(this._apiClient, this._ref);

  Future<String?> _token() => _ref.read(authStateProvider.future);

  Future<List<UserAdmin>> listUsers() async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(UserApiPaths.list, token: token),
    );
    return (data as List<dynamic>).map((e) => UserAdmin.fromJson(e as Map<String, dynamic>)).toList();
  }

  Future<UserAdmin> setRole(int userId, String newRole) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(UserApiPaths.setRole(userId), body: {'role': newRole}, token: token),
    );
    return UserAdmin.fromJson(data);
  }

  Future<UserAdmin> setPremium(int userId, {required bool isPremium}) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(UserApiPaths.setPremium(userId), body: {'isPremium': isPremium}, token: token),
    );
    return UserAdmin.fromJson(data);
  }

  Future<UserAdmin> setRecipeSharing(int userId, {required bool canShareRecipes}) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(
        UserApiPaths.setRecipeSharing(userId),
        body: {'canShareRecipes': canShareRecipes},
        token: token,
      ),
    );
    return UserAdmin.fromJson(data);
  }

  Future<void> updateEmail(int userId, String email) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(
        UserApiPaths.updateEmail(userId),
        body: {'email': email},
        token: token,
      ),
    );
  }

  Future<UserAdmin> createUser({
    required String username,
    required String email,
    required String password,
    String role = 'user',
  }) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.postJson(UserApiPaths.list, body: {
        'username': username,
        'email': email,
        'password': password,
        'role': role,
      }, token: token),
    );
    return UserAdmin.fromJson(data as Map<String, dynamic>);
  }

  Future<void> deleteUser(int userId) async {
    final token = await _token();
    return guardedApiCall(
      _ref,
      () => _apiClient.deleteJson(UserApiPaths.delete(userId), token: token),
    );
  }

  /// Returns `{ temporaryPassword, to, subject, body }`.
  Future<Map<String, dynamic>> resetPassword(int userId) async {
    final token = await _token();
    final result = await guardedApiCall<dynamic>(
      _ref,
      () => _apiClient.postJson(UserApiPaths.resetPassword(userId), token: token),
    );
    return (result as Map<String, dynamic>);
  }

  Future<List<PendingProduct>> listPendingProducts() async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(ProductApiPaths.pending, token: token),
    );
    return (data as List<dynamic>)
        .map((e) => PendingProduct.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  Future<void> setProductStatus(int productId, String status) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(
        ProductApiPaths.setStatus(productId),
        body: {'status': status},
        token: token,
      ),
    );
  }

  Future<List<AiModelInfo>> listAiModels() async {
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(AiApiPaths.models),
    );
    return (data as List<dynamic>)
        .map((e) => AiModelInfo.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  Future<List<AdminProduct>> listProducts() async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(ProductApiPaths.list, token: token),
    );
    return (data as List<dynamic>)
        .map((e) => AdminProduct.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  /// Skapar en ny aktiv produkt (kräver admin). Returnerar `{id, name, categoryId?}`.
  Future<Map<String, dynamic>> createProduct(String name, {int? categoryId}) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.postJson(
        ProductApiPaths.list,
        body: {
          'name': name.trim(),
          if (categoryId != null) 'categoryId': categoryId,
        },
        token: token,
      ),
    );
    return data as Map<String, dynamic>;
  }

  Future<List<AdminProduct>> listDeletedProducts() async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(ProductApiPaths.deleted, token: token),
    );
    return (data as List<dynamic>)
        .map((e) => AdminProduct.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  Future<List<AdminCategoryNode>> listCategoryTree() async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(CategoryApiPaths.tree, token: token),
    );
    return (data as List<dynamic>)
        .map((e) => AdminCategoryNode.fromJson(e as Map<String, dynamic>))
        .toList();
  }

  Future<void> bulkSetCategory(List<int> ids, {required int? categoryId}) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.postJson(
        ProductApiPaths.bulkUpdate,
        body: {'ids': ids, 'categoryId': categoryId},
        token: token,
      ),
    );
  }

  Future<void> setProductCategory(int productId, {required int? categoryId}) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(
        ProductApiPaths.update(productId),
        body: {'categoryId': categoryId},
        token: token,
      ),
    );
  }

  Future<void> removeProduct(int productId) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.deleteJson(ProductApiPaths.remove(productId), token: token),
    );
  }

  Future<void> restoreProduct(int productId) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.postJson(ProductApiPaths.restore(productId), token: token),
    );
  }

  Future<void> mergeProducts({
    required int sourceProductId,
    required int targetProductId,
  }) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.postJson(
        ProductApiPaths.merge,
        body: {
          'sourceProductId': sourceProductId,
          'targetProductId': targetProductId,
        },
        token: token,
      ),
    );
  }

  Future<List<AdminAiCategorizeResult>> aiCategorizeBulk({
    List<int>? productIds,
  }) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.postJson(
        ProductApiPaths.aiCategorizeBulk,
        body: productIds == null || productIds.isEmpty
            ? null
            : {'productIds': productIds},
        token: token,
      ),
    );
    return (data as List<dynamic>)
        .map((e) => AdminAiCategorizeResult.fromJson(e as Map<String, dynamic>))
        .where((e) => e.productId > 0 && e.categoryId > 0)
        .toList();
  }
}
