import 'env_config.dart';

/// Classe utilitaire pour gérer toutes les URLs de l'API backend.
///
/// Cette classe centralise toutes les URLs de l'API pour faciliter
/// la maintenance et éviter la duplication de code.
///
/// **Usage:**
/// ```dart
/// // URL simple
/// final url = Urls.authenticateUser;
///
/// // URL avec paramètres dynamiques
/// final userUrl = Urls.getUserByIdWithId('123');
/// final eventUrl = Urls.getEventByIdWithId('456');
/// ```
class Urls {
  /// Constructeur privé pour empêcher l'instanciation
  Urls._();

  /// URL de base de l'API
  static String get baseUrl => EnvConfig.apiBaseUrl;

  // ============================================================================
  // AUTHENTIFICATION ET UTILISATEURS
  // ============================================================================

  /// Endpoint pour authentifier un utilisateur
  static String get authenticateUser => '$baseUrl/users/authenticate';

  /// Endpoint pour créer un nouvel utilisateur
  static String get createUser => '$baseUrl/users';

  /// Endpoint de base pour les opérations sur les utilisateurs
  static String get usersBase => '$baseUrl/users';

  /// Retourne l'URL pour obtenir un utilisateur par son ID
  ///
  /// [userId] L'ID de l'utilisateur
  static String getUserByIdWithId(String userId) => '$usersBase/$userId';

  /// Retourne l'URL pour rechercher un utilisateur par email
  ///
  /// [email] L'email de l'utilisateur à rechercher
  static String searchUserByEmail(String email) =>
      '$usersBase/search?email=${Uri.encodeComponent(email)}';

  /// Retourne l'URL pour supprimer un utilisateur par son ID
  ///
  /// [userId] L'ID de l'utilisateur
  static String deleteUserWithId(String userId) => '$usersBase/$userId';

  /// Retourne l'URL pour mettre à jour l'image de profil d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String updateUserProfileImageWithId(String userId) =>
      '$usersBase/$userId/profile-image';

  /// Retourne l'URL pour mettre à jour un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String updateUserWithId(String userId) => '$usersBase/$userId';

  // ============================================================================
  // ÉVÉNEMENTS
  // ============================================================================

  /// Endpoint de base pour les opérations sur les événements
  static String get eventsBase => '$baseUrl/events';

  /// Endpoint pour créer un nouvel événement
  static String get createEvent => eventsBase;

  /// Endpoint pour obtenir tous les événements
  static String get getAllEvents => eventsBase;

  /// Endpoint pour obtenir les événements créés par un utilisateur et ses amis
  static String get getEventsCreatedByUserAndFriends =>
      '$eventsBase/created-by-user-and-friends';

  /// Retourne l'URL pour obtenir un événement par son ID
  ///
  /// [eventId] L'ID de l'événement
  static String getEventByIdWithId(String eventId) => '$eventsBase/$eventId';

  /// Retourne l'URL pour supprimer un événement par son ID
  ///
  /// [eventId] L'ID de l'événement
  static String deleteEventWithId(String eventId) => '$eventsBase/$eventId';

  /// Retourne l'URL pour mettre à jour un événement
  ///
  /// [eventId] L'ID de l'événement
  static String updateEventWithId(String eventId) => '$eventsBase/$eventId';

  /// Retourne l'URL pour mettre à jour l'image d'un événement
  ///
  /// [eventId] L'ID de l'événement
  static String updateEventImageWithId(String eventId) =>
      '$eventsBase/$eventId/image';

  /// Retourne l'URL pour fermer un événement
  ///
  /// [eventId] L'ID de l'événement
  static String closeEventWithId(String eventId) => '$eventsBase/$eventId/close';

  /// Retourne l'URL pour rouvrir un événement
  ///
  /// [eventId] L'ID de l'événement
  static String reopenEventWithId(String eventId) =>
      '$eventsBase/$eventId/reopen';

  /// Retourne l'URL pour mettre à jour le statut d'un événement
  ///
  /// [eventId] L'ID de l'événement
  static String updateEventStatusWithId(String eventId) =>
      '$eventsBase/$eventId/status';

  /// Endpoint pour obtenir les événements après une date
  static String get getEventsAfterDate => '$eventsBase/after-date';

  /// Endpoint pour obtenir les événements entre deux dates
  static String get getEventsBetweenDates => '$eventsBase/between-dates';

  /// Retourne l'URL pour obtenir les événements par catégorie
  ///
  /// [category] La catégorie des événements
  static String getEventsByCategoryWithCategory(String category) =>
      '$eventsBase/category/$category';

  /// Retourne l'URL pour obtenir les événements par statut
  ///
  /// [status] Le statut des événements (ouvert, fermé, etc.)
  static String getEventsByStatusWithStatus(String status) =>
      '$eventsBase/status/$status';

  /// Retourne l'URL pour obtenir les événements d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String getEventsByUserWithUserId(String userId) =>
      '$eventsBase/user/$userId';

  /// Retourne l'URL pour obtenir les événements de l'utilisateur et de ses amis
  ///
  /// [userId] L'ID de l'utilisateur
  static String getEventsByFriends(String userId) =>
      '$eventsBase/friends/$userId';

  /// Endpoint pour rechercher des événements
  ///
  /// **Note:** Utilisez des paramètres de requête pour le mot-clé
  static String get searchEvents => '$eventsBase/search';

  // ============================================================================
  // PARTICIPANTS AUX ÉVÉNEMENTS
  // ============================================================================

  /// Retourne l'URL pour ajouter un participant à un événement
  ///
  /// [eventId] L'ID de l'événement
  static String addParticipantWithEventId(String eventId) =>
      '$eventsBase/$eventId/participants';

  /// Retourne l'URL pour retirer un participant d'un événement
  ///
  /// [eventId] L'ID de l'événement
  /// [userId] L'ID de l'utilisateur à retirer
  static String removeParticipantWithIds(String eventId, String userId) =>
      '$eventsBase/$eventId/participants/$userId';

  /// Retourne l'URL pour obtenir le nombre de participants d'un événement
  ///
  /// [eventId] L'ID de l'événement
  static String getNumberOfParticipantsWithEventId(String eventId) =>
      '$eventsBase/$eventId/participants/count';

  /// Retourne l'URL pour réagir à un événement (utilise favorite)
  ///
  /// [eventId] L'ID de l'événement
  /// [userId] L'ID de l'utilisateur
  static String reactToEventWithId(String eventId, String userId) =>
      '$eventsBase/$eventId/favorite?userId=$userId';

  /// Retourne l'URL pour participer à un événement (utilise participants)
  ///
  /// [eventId] L'ID de l'événement
  static String participateInEventWithId(String eventId) =>
      '$eventsBase/$eventId/participants';

  // ============================================================================
  // AMIS ET RELATIONS SOCIALES
  // ============================================================================

  /// Endpoint de base pour les opérations sur les amis
  static String get friendsBase => '$baseUrl/friends';

  /// Retourne l'URL pour obtenir les amis d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String getFriendsWithUserId(String userId) =>
      '$friendsBase/user/$userId';

  /// Retourne l'URL pour ajouter un ami
  ///
  /// [userId] L'ID de l'utilisateur
  /// [friendId] L'ID de l'ami à ajouter
  static String addFriendWithIds(String userId, String friendId) =>
      '$friendsBase/$userId/$friendId';

  /// Retourne l'URL pour supprimer un ami
  ///
  /// [userId] L'ID de l'utilisateur
  /// [friendId] L'ID de l'ami à supprimer
  static String removeFriendWithIds(String userId, String friendId) =>
      '$friendsBase/$userId/$friendId';

  /// Retourne l'URL pour récupérer les demandes d'amitié en attente
  ///
  /// [userId] L'ID de l'utilisateur
  /// [page] Le numéro de la page (optionnel, par défaut 0)
  /// [size] La taille de la page (optionnel, par défaut 10)
  static String getPendingFriendRequestsWithUserId(String userId, {int page = 0, int size = 10}) =>
      '$friendsBase/pending/$userId?page=$page&size=$size';

  /// Retourne l'URL pour récupérer les demandes d'amitié envoyées
  ///
  /// [userId] L'ID de l'utilisateur
  /// [page] Le numéro de la page (optionnel, par défaut 0)
  /// [size] La taille de la page (optionnel, par défaut 10)
  static String getSentFriendRequestsWithUserId(String userId, {int page = 0, int size = 10}) =>
      '$friendsBase/sent/$userId?page=$page&size=$size';

  /// Retourne l'URL pour récupérer les demandes d'amitié reçues
  ///
  /// [userId] L'ID de l'utilisateur
  /// [page] Le numéro de la page (optionnel, par défaut 0)
  /// [size] La taille de la page (optionnel, par défaut 10)
  static String getReceivedFriendRequestsWithUserId(String userId, {int page = 0, int size = 10}) =>
      '$friendsBase/received/$userId?page=$page&size=$size';

  /// Retourne l'URL pour accepter une demande d'amitié
  ///
  /// [friendshipId] L'ID de la relation d'amitié
  static String acceptFriendRequestWithId(String friendshipId) =>
      '$friendsBase/$friendshipId/accept';

  /// Retourne l'URL pour rejeter une demande d'amitié
  ///
  /// [friendshipId] L'ID de la relation d'amitié
  static String rejectFriendRequestWithId(String friendshipId) =>
      '$friendsBase/$friendshipId/reject';

  /// Retourne l'URL pour récupérer les suggestions d'amis
  ///
  /// [userId] L'ID de l'utilisateur
  /// [limit] Nombre maximum de suggestions (optionnel, par défaut 10)
  static String getFriendSuggestionsWithUserId(String userId, {int limit = 10}) =>
      '$friendsBase/suggestions/$userId?limit=$limit';

  // ============================================================================
  // NOTIFICATIONS
  // ============================================================================

  /// Endpoint de base pour les opérations sur les notifications
  static String get notificationsBase => '$baseUrl/notifications';

  /// Retourne l'URL pour obtenir les notifications d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String getNotificationsWithUserId(String userId) =>
      '$notificationsBase/user/$userId';

  /// Retourne l'URL pour marquer une notification comme lue
  ///
  /// [notificationId] L'ID de la notification
  static String markNotificationAsReadWithId(String notificationId) =>
      '$notificationsBase/$notificationId/read';

  /// Retourne l'URL pour marquer toutes les notifications comme lues
  ///
  /// [userId] L'ID de l'utilisateur
  static String markAllNotificationsAsReadWithUserId(String userId) =>
      '$notificationsBase/user/$userId/mark-all-read';

  /// Retourne l'URL pour supprimer une notification
  ///
  /// [notificationId] L'ID de la notification
  static String deleteNotificationWithId(String notificationId) =>
      '$notificationsBase/$notificationId';

  // ============================================================================
  // POSTS SOCIAUX
  // ============================================================================

  /// Endpoint de base pour les opérations sur les posts sociaux
  static String get postsBase => '$baseUrl/posts';

  /// Retourne l'URL pour obtenir tous les posts (avec pagination)
  static String get getAllPosts => postsBase;

  /// Retourne l'URL pour créer un nouveau post
  static String get createSocialPost => postsBase;

  /// Retourne l'URL pour obtenir un post par son ID
  ///
  /// [postId] L'ID du post
  static String getSocialPostByIdWithId(String postId) => '$postsBase/$postId';

  /// Retourne l'URL pour mettre à jour un post
  ///
  /// [postId] L'ID du post
  static String updateSocialPostWithId(String postId) => '$postsBase/$postId';

  /// Retourne l'URL pour supprimer un post
  ///
  /// [postId] L'ID du post
  static String deleteSocialPostWithId(String postId) => '$postsBase/$postId';

  /// Retourne l'URL pour rechercher des posts
  ///
  /// [query] Le terme de recherche
  static String searchSocialPostsWithQuery(String query) =>
      '$postsBase/search?q=${Uri.encodeComponent(query)}';

  /// Retourne l'URL pour liker un post
  ///
  /// [postId] L'ID du post
  static String likeSocialPostWithId(String postId) => '$postsBase/$postId/like';

  /// Retourne l'URL pour commenter un post
  ///
  /// [postId] L'ID du post
  static String commentSocialPostWithId(String postId) =>
      '$postsBase/$postId/comment';

  /// Retourne l'URL pour obtenir tous les commentaires d'un post
  ///
  /// [postId] L'ID du post
  static String getCommentsForPost(String postId) =>
      '$postsBase/$postId/comments';

  /// Retourne l'URL pour partager un post
  ///
  /// [postId] L'ID du post
  static String shareSocialPostWithId(String postId) => '$postsBase/$postId/share';

  /// Retourne l'URL pour obtenir les posts d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String getSocialPostsByUserId(String userId) =>
      '$postsBase/user/$userId';

  /// Retourne l'URL pour obtenir les posts de l'utilisateur et de ses amis
  ///
  /// [userId] L'ID de l'utilisateur
  static String getSocialPostsByFriends(String userId) =>
      '$postsBase/friends/$userId';

  // ============================================================================
  // STORIES
  // ============================================================================

  /// Endpoint de base pour les opérations sur les stories
  static String get storiesBase => '$baseUrl/stories';

  /// Retourne l'URL pour obtenir toutes les stories (actives)
  static String get getAllStories => storiesBase;

  /// Retourne l'URL pour obtenir les stories d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String getStoriesByUserId(String userId) => '$storiesBase/user/$userId';

  /// Retourne l'URL pour créer une nouvelle story
  static String get createStory => storiesBase;

  /// Retourne l'URL pour obtenir une story par son ID
  ///
  /// [storyId] L'ID de la story
  static String getStoryByIdWithId(String storyId) => '$storiesBase/$storyId';

  /// Retourne l'URL pour supprimer une story
  ///
  /// [storyId] L'ID de la story
  static String deleteStoryWithId(String storyId) => '$storiesBase/$storyId';

  /// Retourne l'URL pour marquer une story comme vue
  ///
  /// [storyId] L'ID de la story
  /// [userId] L'ID de l'utilisateur qui voit la story
  static String markStoryAsViewedWithId(String storyId, String userId) =>
      '$storiesBase/$storyId/view?userId=$userId';

  /// Retourne l'URL pour obtenir les vues d'une story
  ///
  /// [storyId] L'ID de la story
  static String getStoryViewsWithId(String storyId) => '$storiesBase/$storyId/views';

  // ============================================================================
  // MESSAGERIE
  // ============================================================================

  /// Endpoint de base pour les opérations sur les messages
  static String get messagesBase => '$baseUrl/messages';

  /// Retourne l'URL pour envoyer un message
  static String get sendMessage => messagesBase;

  /// Retourne l'URL pour obtenir les conversations d'un utilisateur
  ///
  /// [userId] L'ID de l'utilisateur
  static String getUserConversations(String userId) =>
      '$messagesBase/conversations/$userId';

  /// Retourne l'URL pour obtenir les messages d'une conversation
  ///
  /// [conversationId] L'ID de la conversation
  /// [page] Le numéro de la page (optionnel)
  /// [size] La taille de la page (optionnel)
  static String getConversationMessages(String conversationId,
          {int page = 0, int size = 50}) =>
      '$messagesBase/conversation/$conversationId?page=$page&size=$size';

  /// Retourne l'URL pour obtenir une conversation entre deux utilisateurs
  ///
  /// [user1Id] L'ID du premier utilisateur
  /// [user2Id] L'ID du deuxième utilisateur
  static String getConversationBetweenUsers(String user1Id, String user2Id) =>
      '$messagesBase/conversation/between/$user1Id/$user2Id';

  /// Retourne l'URL pour marquer un message comme lu
  ///
  /// [messageId] L'ID du message
  static String markMessageAsRead(String messageId) =>
      '$messagesBase/$messageId/read';

  /// Retourne l'URL pour marquer tous les messages d'une conversation comme lus
  ///
  /// [conversationId] L'ID de la conversation
  /// [userId] L'ID de l'utilisateur
  static String markAllMessagesAsRead(String conversationId, String userId) =>
      '$messagesBase/conversation/$conversationId/read/$userId';

  /// Retourne l'URL pour obtenir le nombre de messages non lus
  ///
  /// [userId] L'ID de l'utilisateur
  static String getUnreadMessagesCount(String userId) =>
      '$messagesBase/unread/count/$userId';

  /// Retourne l'URL pour supprimer un message
  ///
  /// [messageId] L'ID du message
  static String deleteMessage(String messageId) => '$messagesBase/$messageId';

  /// Retourne l'URL pour supprimer une conversation
  ///
  /// [conversationId] L'ID de la conversation
  static String deleteConversation(String conversationId) =>
      '$messagesBase/conversation/$conversationId';

  /// Retourne l'URL WebSocket pour le chat en temps réel
  ///
  /// [userId] L'ID de l'utilisateur
  static String getChatWebSocketUrl(String userId) {
    final wsUrl = baseUrl
        .replaceFirst('http://', 'ws://')
        .replaceFirst('https://', 'wss://');
    return '$wsUrl/chat/ws/$userId';
  }

  // ============================================================================
  // MÉTHODES UTILITAIRES
  // ============================================================================

  /// Construit une URL avec des paramètres de requête
  ///
  /// [baseUrl] L'URL de base
  /// [params] Les paramètres de requête (clé-valeur)
  ///
  /// **Exemple:**
  /// ```dart
  /// final url = Urls.buildUrlWithParams(
  ///   Urls.searchEvents,
  ///   {'keyword': 'concert', 'category': 'music'},
  /// );
  /// // Résultat: 'http://api.com/events/search?keyword=concert&category=music'
  /// ```
  static String buildUrlWithParams(String baseUrl, Map<String, String> params) {
    if (params.isEmpty) return baseUrl;

    final queryString = params.entries
        .map((e) => '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
        .join('&');

    return '$baseUrl?$queryString';
  }

  /// Valide qu'une URL est bien formée
  ///
  /// [url] L'URL à valider
  ///
  /// Returns `true` si l'URL est valide, `false` sinon
  static bool isValidUrl(String url) {
    try {
      final uri = Uri.parse(url);
      return uri.hasScheme && uri.hasAuthority;
    } catch (e) {
      return false;
    }
  }
}
