/// Datasource distant pour la communication (API)
library messaging_remote_datasource;

import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:injectable/injectable.dart';
import '../../../../core/config/environment.dart';
import '../../../../core/error/exceptions.dart';
import '../models/message_model.dart';
import '../models/conversation_model.dart';
import '../../domain/entities/message.dart';

@lazySingleton
class MessagingRemoteDatasource {
  final http.Client client;
  final FlutterSecureStorage secureStorage;

  MessagingRemoteDatasource({
    required this.client,
    required this.secureStorage,
  });

  /// Headers HTTP avec authentification
  Future<Map<String, String>> _getHeaders() async {
    final token = await secureStorage.read(key: 'access_token');
    return {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      if (token != null) 'Authorization': 'Bearer $token',
    };
  }

  // === CONVERSATIONS ===

  Future<List<ConversationModel>> getConversations({
    String? organizationId,
    bool includeArchived = false,
  }) async {
    final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/conversations')
        .replace(queryParameters: {
      if (organizationId != null) 'organizationId': organizationId,
      'includeArchived': includeArchived.toString(),
    });

    final response = await client.get(uri, headers: await _getHeaders());

    if (response.statusCode == 200) {
      final List<dynamic> jsonList = json.decode(response.body);
      return jsonList
          .map((json) => ConversationModel.fromJson(json))
          .toList();
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else {
      throw ServerException('Erreur lors de la récupération des conversations');
    }
  }

  Future<ConversationModel> getConversationById(String conversationId) async {
    final uri = Uri.parse(
        '${AppConfig.apiBaseUrl}/api/messaging/conversations/$conversationId');

    final response = await client.get(uri, headers: await _getHeaders());

    if (response.statusCode == 200) {
      return ConversationModel.fromJson(json.decode(response.body));
    } else if (response.statusCode == 404) {
      throw NotFoundException('Conversation non trouvée');
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else {
      throw ServerException('Erreur lors de la récupération de la conversation');
    }
  }

  Future<ConversationModel> createConversation({
    required String name,
    required List<String> participantIds,
    String? organizationId,
    String? description,
  }) async {
    final uri =
        Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/conversations');

    final body = json.encode({
      'name': name,
      'participantIds': participantIds,
      if (organizationId != null) 'organizationId': organizationId,
      if (description != null) 'description': description,
    });

    final response = await client.post(
      uri,
      headers: await _getHeaders(),
      body: body,
    );

    if (response.statusCode == 201 || response.statusCode == 200) {
      return ConversationModel.fromJson(json.decode(response.body));
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else {
      throw ServerException('Erreur lors de la création de la conversation');
    }
  }

  // === MESSAGES ===

  Future<List<MessageModel>> getMessages({
    required String conversationId,
    int? limit,
    String? beforeMessageId,
  }) async {
    final uri = Uri.parse(
        '${AppConfig.apiBaseUrl}/api/messaging/conversations/$conversationId/messages')
        .replace(queryParameters: {
      if (limit != null) 'limit': limit.toString(),
      if (beforeMessageId != null) 'beforeMessageId': beforeMessageId,
    });

    final response = await client.get(uri, headers: await _getHeaders());

    if (response.statusCode == 200) {
      final List<dynamic> jsonList = json.decode(response.body);
      return jsonList.map((json) => MessageModel.fromJson(json)).toList();
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else {
      throw ServerException('Erreur lors de la récupération des messages');
    }
  }

  Future<MessageModel> sendMessage({
    required String conversationId,
    required String content,
    List<String>? attachments,
    MessagePriority priority = MessagePriority.normal,
  }) async {
    final uri = Uri.parse(
        '${AppConfig.apiBaseUrl}/api/messaging/conversations/$conversationId/messages');

    final body = json.encode({
      'content': content,
      if (attachments != null) 'attachments': attachments,
      'priority': priority.name,
    });

    final response = await client.post(
      uri,
      headers: await _getHeaders(),
      body: body,
    );

    if (response.statusCode == 201 || response.statusCode == 200) {
      return MessageModel.fromJson(json.decode(response.body));
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else {
      throw ServerException('Erreur lors de l\'envoi du message');
    }
  }

  Future<MessageModel> sendBroadcast({
    required String organizationId,
    required String subject,
    required String content,
    MessagePriority priority = MessagePriority.normal,
    List<String>? attachments,
  }) async {
    final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/broadcast');

    final body = json.encode({
      'organizationId': organizationId,
      'subject': subject,
      'content': content,
      'priority': priority.name,
      if (attachments != null) 'attachments': attachments,
    });

    final response = await client.post(
      uri,
      headers: await _getHeaders(),
      body: body,
    );

    if (response.statusCode == 201 || response.statusCode == 200) {
      return MessageModel.fromJson(json.decode(response.body));
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else if (response.statusCode == 403) {
      throw ForbiddenException('Permission insuffisante pour envoyer un broadcast');
    } else {
      throw ServerException('Erreur lors de l\'envoi du broadcast');
    }
  }

  Future<void> markMessageAsRead(String messageId) async {
    final uri =
        Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/messages/$messageId/read');

    final response = await client.put(uri, headers: await _getHeaders());

    if (response.statusCode != 200 && response.statusCode != 204) {
      if (response.statusCode == 401) {
        throw UnauthorizedException();
      } else {
        throw ServerException('Erreur lors du marquage du message comme lu');
      }
    }
  }

  Future<int> getUnreadCount({String? organizationId}) async {
    final uri = Uri.parse('${AppConfig.apiBaseUrl}/api/messaging/unread/count')
        .replace(queryParameters: {
      if (organizationId != null) 'organizationId': organizationId,
    });

    final response = await client.get(uri, headers: await _getHeaders());

    if (response.statusCode == 200) {
      final data = json.decode(response.body);
      return data['count'] as int;
    } else if (response.statusCode == 401) {
      throw UnauthorizedException();
    } else {
      throw ServerException('Erreur lors de la récupération du compte non lu');
    }
  }
}
