import 'dart:convert';
import 'package:afterwork/core/constants/urls.dart';
import 'package:afterwork/data/models/event_model.dart';
import 'package:http/http.dart' as http;
import '../../core/errors/exceptions.dart';

/// Source de données pour les événements distants.
class EventRemoteDataSource {
  final http.Client client;

  EventRemoteDataSource(this.client);

  /// Récupérer tous les événements depuis l'API.
  Future<List<EventModel>> getAllEvents() async {
    print('Récupération de tous les événements depuis ${Urls.baseUrl}/events');

    final response = await client.get(Uri.parse('${Urls.baseUrl}/events'));

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 200) {
      final List<dynamic> jsonResponse = json.decode(response.body);
      print('Réponse JSON reçue: $jsonResponse');
      return jsonResponse.map((event) => EventModel.fromJson(event)).toList();
    } else {
      print('Erreur lors de la récupération des événements: ${response.body}');
      throw ServerException();
    }
  }

  /// Créer un nouvel événement via l'API.
  Future<EventModel> createEvent(EventModel event) async {
    print('Création d\'un nouvel événement avec les données: ${event.toJson()}');

    final response = await client.post(
      Uri.parse(Urls.createEvent),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(event.toJson()),
    );

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 201) {
      print('Événement créé avec succès');
      return EventModel.fromJson(json.decode(response.body));
    } else {
      print('Erreur lors de la création de l\'événement: ${response.body}');
      throw ServerException();
    }
  }

  /// Récupérer un événement spécifique par son ID.
  Future<EventModel> getEventById(String id) async {
    print('Récupération de l\'événement avec l\'ID: $id');

    final response = await client.get(Uri.parse('${Urls.getEventById}/$id'));

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 200) {
      print('Événement récupéré avec succès');
      return EventModel.fromJson(json.decode(response.body));
    } else {
      print('Erreur lors de la récupération de l\'événement: ${response.body}');
      throw ServerException();
    }
  }

  /// Mettre à jour un événement existant.
  Future<EventModel> updateEvent(String id, EventModel event) async {
    print('Mise à jour de l\'événement avec l\'ID: $id, données: ${event.toJson()}');

    final response = await client.put(
      Uri.parse('${Urls.updateEvent}/$id'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode(event.toJson()),
    );

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 200) {
      print('Événement mis à jour avec succès');
      return EventModel.fromJson(json.decode(response.body));
    } else {
      print('Erreur lors de la mise à jour de l\'événement: ${response.body}');
      throw ServerException();
    }
  }

  /// Supprimer un événement par son ID.
  Future<void> deleteEvent(String id) async {
    print('Suppression de l\'événement avec l\'ID: $id');

    final response = await client.delete(Uri.parse('${Urls.deleteEvent}/$id'));

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode != 204) {
      print('Erreur lors de la suppression de l\'événement: ${response.body}');
      throw ServerException();
    } else {
      print('Événement supprimé avec succès');
    }
  }

  /// Participer à un événement.
  Future<EventModel> participateInEvent(String eventId, String userId) async {
    print('Participation à l\'événement avec l\'ID: $eventId, utilisateur: $userId');

    final response = await client.post(
      Uri.parse('${Urls.addParticipant}/$eventId/participate'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'userId': userId}),
    );

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 200) {
      print('Participation réussie');
      return EventModel.fromJson(json.decode(response.body));
    } else {
      print('Erreur lors de la participation à l\'événement: ${response.body}');
      throw ServerException();
    }
  }

  /// Réagir à un événement.
  Future<void> reactToEvent(String eventId, String userId) async {
    print('Réaction à l\'événement avec l\'ID: $eventId, utilisateur: $userId');

    final response = await client.post(
      Uri.parse('${Urls.baseUrl}/$eventId/react'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'userId': userId}),
    );

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode != 200) {
      print('Erreur lors de la réaction à l\'événement: ${response.body}');
      throw ServerException();
    } else {
      print('Réaction réussie');
    }
  }

  /// Fermer un événement.
  Future<void> closeEvent(String eventId) async {
    print('Fermeture de l\'événement avec l\'ID: $eventId');

    final response = await client.post(
      Uri.parse('${Urls.closeEvent}/$eventId/close'),
      headers: {'Content-Type': 'application/json'},
    );

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 200) {
      print('Événement fermé avec succès');
    } else if (response.statusCode == 400) {
      // Si le serveur retourne une erreur 400, vérifiez le corps du message
      final responseBody = json.decode(response.body);
      final errorMessage = responseBody['message'] ?? 'Erreur inconnue';
      print('Erreur lors de la fermeture de l\'événement: $errorMessage');
      throw ServerExceptionWithMessage(errorMessage); // Utiliser la nouvelle exception ici
    } else {
      print('Erreur lors de la fermeture de l\'événement: ${response.body}');
      throw ServerExceptionWithMessage('Une erreur est survenue lors de la fermeture de l\'événement.');
    }
  }

  /// Rouvrir un événement.
  Future<void> reopenEvent(String eventId) async {
    print('Réouverture de l\'événement avec l\'ID: $eventId');

    final response = await client.post(
      Uri.parse('${Urls.reopenEvent}/$eventId/reopen'),
      headers: {'Content-Type': 'application/json'},
    );

    print('Statut de la réponse: ${response.statusCode}');

    if (response.statusCode == 200) {
      print('Événement rouvert avec succès');
    } else if (response.statusCode == 400) {
      // Si le serveur retourne une erreur 400, vérifiez le corps du message
      final responseBody = json.decode(response.body);
      final errorMessage = responseBody['message'] ?? 'Erreur inconnue';
      print('Erreur lors de la réouverture de l\'événement: $errorMessage');
      throw ServerExceptionWithMessage(errorMessage);
    } else {
      print('Erreur lors de la réouverture de l\'événement: ${response.body}');
      throw ServerExceptionWithMessage('Une erreur est survenue lors de la réouverture de l\'événement.');
    }
  }

}
