import 'package:dio/dio.dart';
import 'package:injectable/injectable.dart';

import 'package:unionflow_mobile_apps/core/network/api_client.dart';
import 'package:unionflow_mobile_apps/core/utils/logger.dart';
import '../../domain/entities/network_item.dart';

/// Repository pour la recherche réseau (membres + organisations).
/// Délègue la recherche au backend Quarkus.
@lazySingleton
class NetworkRepository {
  final ApiClient _apiClient;

  NetworkRepository(this._apiClient);

  List<dynamic> _parseListResponse(dynamic data) {
    if (data is List) return data;
    if (data is Map && data.containsKey('content')) {
      final content = data['content'];
      return content is List ? content : [];
    }
    return [];
  }

  /// Recherche de membres (GET /api/membres/recherche?q=...)
  Future<List<NetworkItem>> searchMembers(String query, {int page = 0, int size = 20}) async {
    if (query.trim().isEmpty) return [];
    try {
      final response = await _apiClient.get(
        '/api/membres/recherche',
        queryParameters: {'q': query.trim(), 'page': page, 'size': size},
      );
      final data = _parseListResponse(response.data);
      return data.map((json) => _memberFromJson(json as Map<String, dynamic>)).toList();
    } on DioException catch (e) {
      if (e.response?.statusCode == 400) return [];
      rethrow;
    }
  }

  /// Recherche d'organisations (GET /api/organisations/recherche?nom=...)
  Future<List<NetworkItem>> searchOrganizations(String query, {int page = 0, int size = 20}) async {
    if (query.trim().isEmpty) return [];
    try {
      final response = await _apiClient.get(
        '/api/organisations/recherche',
        queryParameters: {'nom': query.trim(), 'page': page, 'size': size},
      );
      final data = _parseListResponse(response.data);
      return data.map((json) => _organisationFromJson(json as Map<String, dynamic>)).toList();
    } on DioException catch (e) {
      if (e.response?.statusCode == 400) return [];
      rethrow;
    }
  }

  /// Recherche globale : membres + organisations (deux appels parallèles).
  /// Si [followedIds] est fourni, les membres dont l'id est dans le set auront [isConnected: true].
  Future<List<NetworkItem>> search(String query, {int page = 0, int size = 10, Set<String>? followedIds}) async {
    if (query.trim().isEmpty) return [];
    try {
      final results = await Future.wait([
        searchMembers(query, page: page, size: size),
        searchOrganizations(query, page: page, size: size),
      ]);
      final members = results[0].map((m) {
        if (followedIds != null && followedIds.contains(m.id)) return m.copyWith(isConnected: true);
        return m;
      }).toList();
      final orgs = results[1];
      return [...members, ...orgs];
    } catch (e) {
      rethrow;
    }
  }

  /// Liste des ids des membres suivis par l'utilisateur connecté (GET /api/membres/me/suivis).
  Future<List<String>> getFollowedIds() async {
    try {
      final response = await _apiClient.get('/api/membres/me/suivis');
      if (response.statusCode != 200) return [];
      final data = response.data;
      if (data is! List) return [];
      return data.map((e) => e.toString()).toList();
    } on DioException catch (e) {
      if (e.response?.statusCode == 401 || e.response?.statusCode == 403) return [];
      AppLogger.error('NetworkRepository: getFollowedIds échoué', error: e);
      rethrow;
    }
  }

  /// Suivre un membre (POST /api/membres/{id}/suivre). Retourne true si following après l'appel.
  Future<bool> follow(String memberId) async {
    try {
      final response = await _apiClient.post('/api/membres/$memberId/suivre');
      if (response.statusCode == 200 && response.data is Map) {
        return (response.data as Map)['following'] == true;
      }
      return false;
    } on DioException catch (e, st) {
      AppLogger.error('NetworkRepository: follow échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  /// Ne plus suivre un membre (DELETE /api/membres/{id}/suivre). Retourne false (plus suivi).
  Future<bool> unfollow(String memberId) async {
    try {
      final response = await _apiClient.delete('/api/membres/$memberId/suivre');
      if (response.statusCode == 200 && response.data is Map) {
        return (response.data as Map)['following'] == true;
      }
      return false;
    } on DioException catch (e, st) {
      AppLogger.error('NetworkRepository: unfollow échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  static NetworkItem _memberFromJson(Map<String, dynamic> json) {
    final id = json['id']?.toString() ?? '';
    final prenom = json['prenom']?.toString() ?? '';
    final nom = json['nom']?.toString() ?? '';
    final name = '$prenom $nom'.trim().isEmpty ? (json['numeroMembre']?.toString() ?? id) : '$prenom $nom'.trim();
    return NetworkItem(
      id: id,
      name: name,
      subtitle: json['profession']?.toString() ?? json['statutCompteLibelle']?.toString(),
      avatarUrl: null,
      type: 'Member',
      isConnected: false,
    );
  }

  static NetworkItem _organisationFromJson(Map<String, dynamic> json) {
    final id = json['id']?.toString() ?? '';
    return NetworkItem(
      id: id,
      name: json['nom']?.toString() ?? json['nomCourt']?.toString() ?? 'Organisation',
      subtitle: json['typeOrganisationLibelle']?.toString() ?? json['statutLibelle']?.toString(),
      avatarUrl: null,
      type: 'Organization',
      isConnected: false,
    );
  }
}
