import 'package:flutter/foundation.dart';
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/receipt_alias.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);

  // ── Interna helpers ────────────────────────────────────────────────────────

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

  /// GET-anrop som returnerar en typad lista med [fromJson].
  Future<List<T>> _getList<T>(
    String path,
    T Function(Map<String, dynamic>) fromJson, {
    bool requiresAuth = true,
  }) async {
    final token = requiresAuth ? await _token() : null;
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(path, token: token),
    );
    return _parseList(data, fromJson);
  }

  /// POST-anrop som returnerar ett typad objekt med [fromJson].
  Future<T> _post<T>(
    String path, {
    required Map<String, dynamic>? body,
    required T Function(dynamic) parse,
    bool requiresAuth = true,
  }) async {
    final token = requiresAuth ? await _token() : null;
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.postJson(path, body: body, token: token),
    );
    return parse(data);
  }

  /// PATCH-anrop som returnerar ett typad objekt med [fromJson].
  Future<T> _patch<T>(
    String path, {
    required Map<String, dynamic> body,
    required T Function(Map<String, dynamic>) parse,
  }) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(path, body: body, token: token),
    );
    return parse(Map<String, dynamic>.from(data as Map));
  }

  /// Fire-and-forget PATCH.
  Future<void> _patchVoid(String path, Map<String, dynamic> body) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.patchJson(path, body: body, token: token),
    );
  }

  /// Fire-and-forget POST.
  Future<void> _postVoid(String path, [Map<String, dynamic>? body]) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.postJson(path, body: body, token: token),
    );
  }

  /// Fire-and-forget DELETE.
  Future<void> _deleteVoid(String path) async {
    final token = await _token();
    await guardedApiCall(
      _ref,
      () => _apiClient.deleteJson(path, token: token),
    );
  }

  /// Tolerant listparsning — accepterar ren lista eller wrapper ({items, data}).
  static List<T> _parseList<T>(
    dynamic data,
    T Function(Map<String, dynamic>) fromJson,
  ) {
    final List<dynamic> raw;
    if (data is List<dynamic>) {
      raw = data;
    } else if (data is Map<String, dynamic>) {
      raw = (data['items'] as List<dynamic>?) ??
          (data['data'] as List<dynamic>?) ??
          const [];
      if (raw.isEmpty && data.isNotEmpty) {
        debugPrint('[AdminRepository] Unexpected API wrapper shape: ${data.keys}');
      }
    } else {
      raw = const [];
    }
    return raw
        .whereType<Map>()
        .map((e) => fromJson(Map<String, dynamic>.from(e)))
        .toList();
  }

  // ── Användare ──────────────────────────────────────────────────────────────

  Future<List<UserAdmin>> listUsers() =>
      _getList(UserApiPaths.list, UserAdmin.fromJson);

  Future<UserAdmin> setRole(int userId, String newRole) =>
      _patch(UserApiPaths.setRole(userId),
          body: {'role': newRole}, parse: UserAdmin.fromJson);

  Future<UserAdmin> setPremium(int userId, {required bool isPremium}) =>
      _patch(UserApiPaths.setPremium(userId),
          body: {'isPremium': isPremium}, parse: UserAdmin.fromJson);

  Future<UserAdmin> setRecipeSharing(int userId,
          {required bool canShareRecipes}) =>
      _patch(UserApiPaths.setRecipeSharing(userId),
          body: {'canShareRecipes': canShareRecipes}, parse: UserAdmin.fromJson);

  Future<void> updateEmail(int userId, String email) =>
      _patchVoid(UserApiPaths.updateEmail(userId), {'email': email});

  Future<UserAdmin> createUser({
    required String username,
    required String email,
    required String password,
    String role = 'user',
  }) =>
      _post(
        UserApiPaths.list,
        body: {
          'username': username,
          'email': email,
          'password': password,
          'role': role,
        },
        parse: (d) => UserAdmin.fromJson(d as Map<String, dynamic>),
      );

  Future<void> deleteUser(int userId) => _deleteVoid(UserApiPaths.delete(userId));

  /// Returns `{ temporaryPassword, to, subject, body }`.
  Future<Map<String, dynamic>> resetPassword(int userId) =>
      _post<Map<String, dynamic>>(
        UserApiPaths.resetPassword(userId),
        body: null,
        parse: (d) => d as Map<String, dynamic>,
      );

  // ── Produkter ──────────────────────────────────────────────────────────────

  Future<List<AdminProduct>> listProducts() =>
      _getList(ProductApiPaths.mine, AdminProduct.fromJson);

  Future<List<AdminProduct>> listDeletedProducts() =>
      _getList(ProductApiPaths.deleted, AdminProduct.fromJson);

  Future<List<PendingProduct>> listPendingProducts() =>
      _getList(ProductApiPaths.pending, PendingProduct.fromJson);

  Future<void> setProductStatus(int productId, String status) =>
      _patchVoid(ProductApiPaths.setStatus(productId), {'status': status});

  Future<void> setProductCategory(int productId, {required int? categoryId}) =>
      _patchVoid(ProductApiPaths.update(productId), {'categoryId': categoryId});

  Future<void> removeProduct(int productId) =>
      _deleteVoid(ProductApiPaths.remove(productId));

  Future<void> restoreProduct(int productId) =>
      _postVoid(ProductApiPaths.restore(productId));

  /// Skapar en ny aktiv produkt (kräver admin). Returnerar `{id, name, categoryId?}`.
  Future<Map<String, dynamic>> createProduct(String name, {int? categoryId}) =>
      _post<Map<String, dynamic>>(
        ProductApiPaths.list,
        body: {
          'name': name.trim(),
          if (categoryId != null) 'categoryId': categoryId,
        },
        parse: (d) => d as Map<String, dynamic>,
      );

  Future<void> bulkSetCategory(List<int> ids, {required int? categoryId}) =>
      _postVoid(ProductApiPaths.bulkUpdate, {'ids': ids, 'categoryId': categoryId});

  Future<void> mergeProducts({
    required int sourceProductId,
    required int targetProductId,
  }) =>
      _postVoid(ProductApiPaths.merge, {
        'sourceProductId': sourceProductId,
        'targetProductId': targetProductId,
      });

  Future<Map<String, dynamic>> previewMerge({
    required int sourceProductId,
    required int targetProductId,
  }) async {
    final token = await _token();
    final data = await guardedApiCall(
      _ref,
      () => _apiClient.getJson(
        ProductApiPaths.mergePreview(sourceProductId, targetProductId),
        token: token,
      ),
    );
    return Map<String, dynamic>.from(data as Map);
  }

  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 _parseList(data, AdminAiCategorizeResult.fromJson)
        .where((e) => e.productId > 0 && e.categoryId > 0)
        .toList();
  }

  // ── Kategorier ─────────────────────────────────────────────────────────────

  Future<List<AdminCategoryNode>> listCategoryTree() =>
      _getList(
        CategoryApiPaths.tree,
        AdminCategoryNode.fromJson,
        requiresAuth: false,
      );

  // ── AI-modeller ────────────────────────────────────────────────────────────

  /// OBS: endpointen /ai/models kräver autentisering.
  Future<List<AiModelInfo>> listAiModels() =>
      _getList(AiApiPaths.models, AiModelInfo.fromJson);

  // ── Kvittoalias (admin/global fallback) ───────────────────────────────────

  Future<List<ReceiptAlias>> listReceiptAliases() =>
      _getList(ReceiptAliasApiPaths.list, ReceiptAlias.fromJson);

  Future<void> upsertReceiptAlias({
    required String receiptName,
    required int productId,
    bool isGlobal = false,
  }) =>
      _postVoid(ReceiptAliasApiPaths.list, {
        'receiptName': receiptName,
        'productId': productId,
        'isGlobal': isGlobal,
      });

  Future<void> removeReceiptAlias(int id) =>
      _deleteVoid(ReceiptAliasApiPaths.remove(id));
}
