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 '../models/compte_epargne_model.dart';
import '../models/transaction_epargne_request.dart';

/// Repository des comptes épargne — API /api/v1/epargne/comptes.
@lazySingleton
class CompteEpargneRepository {
  final ApiClient _apiClient;
  static const String _baseComptes = '/api/v1/epargne/comptes';

  CompteEpargneRepository(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 [];
  }

  /// Comptes épargne du membre connecté (GET /api/v1/epargne/comptes/mes-comptes).
  Future<List<CompteEpargneModel>> getMesComptes() async {
    try {
      final response = await _apiClient.get('$_baseComptes/mes-comptes');
      if (response.statusCode == 200) {
        final data = _parseListResponse(response.data);
        return data.map((e) => CompteEpargneModel.fromJson(e as Map<String, dynamic>)).toList();
      }
      AppLogger.error('CompteEpargneRepository: getMesComptes status ${response.statusCode}');
      throw Exception('Impossible de charger les comptes: ${response.statusCode}');
    } catch (e, st) {
      AppLogger.error('CompteEpargneRepository: getMesComptes échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  Future<List<CompteEpargneModel>> getByMembre(String membreId) async {
    try {
      final response = await _apiClient.get('$_baseComptes/membre/$membreId');
      if (response.statusCode == 200) {
        final data = _parseListResponse(response.data);
        return data.map((e) => CompteEpargneModel.fromJson(e as Map<String, dynamic>)).toList();
      }
      AppLogger.error('CompteEpargneRepository: getByMembre status ${response.statusCode}');
      throw Exception('Impossible de charger les comptes du membre: ${response.statusCode}');
    } catch (e, st) {
      AppLogger.error('CompteEpargneRepository: getByMembre échoué', error: e, stackTrace: st);
      rethrow;
    }
  }

  Future<CompteEpargneModel?> getById(String id) async {
    final response = await _apiClient.get('$_baseComptes/$id');
    if (response.statusCode == 200) {
      return CompteEpargneModel.fromJson(response.data as Map<String, dynamic>);
    }
    return null;
  }

  /// Crée un compte épargne pour un membre (réservé admin / admin organisation).
  /// POST /api/v1/epargne/comptes
  Future<CompteEpargneModel> creerCompte({
    required String membreId,
    required String organisationId,
    required String typeCompte,
    String? notesOuverture,
  }) async {
    final body = <String, dynamic>{
      'membreId': membreId,
      'organisationId': organisationId,
      'typeCompte': typeCompte,
    };
    if (notesOuverture != null && notesOuverture.isNotEmpty) {
      body['notesOuverture'] = notesOuverture;
    }
    final response = await _apiClient.post(_baseComptes, data: body);
    if (response.statusCode == 201 || response.statusCode == 200) {
      return CompteEpargneModel.fromJson(response.data as Map<String, dynamic>);
    }
    throw Exception('Erreur création compte épargne: ${response.statusCode}');
  }
}

/// Repository des transactions épargne — API /api/v1/epargne/transactions.
/// LCB-FT : le backend exige origineFonds au-dessus du seuil configuré.
@lazySingleton
class TransactionEpargneRepository {
  final ApiClient _apiClient;
  static const String _base = '/api/v1/epargne/transactions';

  TransactionEpargneRepository(this._apiClient);

  /// Exécute une transaction (dépôt, retrait, etc.).
  Future<Map<String, dynamic>> executer(TransactionEpargneRequest request) async {
    final response = await _apiClient.post(_base, data: request.toJson());
    if (response.statusCode == 201 || response.statusCode == 200) {
      return response.data as Map<String, dynamic>;
    }
    throw Exception('Erreur transaction épargne: ${response.statusCode}');
  }

  /// Transfert entre deux comptes.
  Future<Map<String, dynamic>> transferer(TransactionEpargneRequest request) async {
    final response = await _apiClient.post('$_base/transfert', data: request.toJson());
    if (response.statusCode == 201 || response.statusCode == 200) {
      return response.data as Map<String, dynamic>;
    }
    throw Exception('Erreur transfert: ${response.statusCode}');
  }

  /// Historique des transactions d'un compte (paginé).
  Future<List<Map<String, dynamic>>> getByCompte(
    String compteId, {
    int page = 0,
    int size = 20,
  }) async {
    final response = await _apiClient.get(
      '$_base/compte/$compteId',
      queryParameters: {'page': page, 'size': size},
    );
    if (response.statusCode == 200) {
      final data = response.data;
      if (data is List) return List<Map<String, dynamic>>.from(data.map((e) => e as Map<String, dynamic>));
      if (data is Map && data.containsKey('content')) {
        final content = data['content'] as List? ?? [];
        return List<Map<String, dynamic>>.from(content.map((e) => e as Map<String, dynamic>));
      }
      return [];
    }
    throw Exception('Erreur chargement historique: ${response.statusCode}');
  }

  /// Initie un dépôt sur compte épargne via Wave (même API que cotisations).
  /// Retourne l'URL à ouvrir (wave_launch_url) pour confirmer dans l'app Wave.
  Future<DepotWaveResult> initierDepotEpargneEnLigne({
    required String compteId,
    required double montant,
    required String numeroTelephone,
  }) async {
    final response = await _apiClient.post(
      '/api/versements/initier-depot-epargne',
      data: {
        'compteId': compteId,
        'montant': montant,
        'numeroTelephone': numeroTelephone.replaceAll(RegExp(r'\D'), ''),
      },
    );
    if (response.statusCode != 201 && response.statusCode != 200) {
      final msg = response.data is Map
          ? (response.data['message'] ?? response.data['error'] ?? response.statusCode)
          : response.statusCode;
      throw Exception('Impossible d\'initier le dépôt: $msg');
    }
    final data = response.data is Map<String, dynamic>
        ? response.data as Map<String, dynamic>
        : Map<String, dynamic>.from(response.data as Map);
    return DepotWaveResult(
      waveLaunchUrl: data['waveLaunchUrl'] as String? ?? data['redirectUrl'] as String? ?? '',
      redirectUrl: data['redirectUrl'] as String? ?? data['waveLaunchUrl'] as String? ?? '',
      message: data['message'] as String? ?? 'Ouvrez Wave pour confirmer le dépôt.',
      versementId: data['versementId'] as String? ?? data['clientReference'] as String? ?? '',
    );
  }

  /// Confirme un paiement mock (mode dev) côté backend.
  /// Appelle GET /api/wave-redirect/mock-complete?ref={id}
  /// pour que le backend crédite réellement le compte.
  Future<void> confirmerMockPaiement(String versementId) async {
    await _apiClient.get('/api/wave-redirect/mock-complete', queryParameters: {'ref': versementId});
  }
}

/// Résultat de l'initiation d'un dépôt Wave (épargne).
class DepotWaveResult {
  final String waveLaunchUrl;
  final String redirectUrl;
  final String message;
  final String versementId;

  const DepotWaveResult({
    required this.waveLaunchUrl,
    required this.redirectUrl,
    required this.message,
    this.versementId = '',
  });
}
