import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logger/logger.dart';
import 'package:real_estate_mobile/core/constants/api_constants.dart';
import 'package:real_estate_mobile/core/network/api_client.dart';
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
import 'package:real_estate_mobile/features/messaging/data/models/messaging_models.dart';

final _log = Logger(printer: PrettyPrinter(methodCount: 0));

class MessagingRepository {
  final Dio _dio = ApiClient.instance.dio;

  /// GET /messages/conversations
  Future<List<Conversation>> getConversations() async {
    try {
      final response = await _dio.get(ApiConstants.conversations);
      final data = response.data['data'] as List<dynamic>;
      return data
          .map((e) => Conversation.fromJson(e as Map<String, dynamic>))
          .toList();
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to fetch conversations',
        statusCode: e.response?.statusCode,
      );
    } catch (e, stack) {
      _log.e('Conversation parsing error', error: e, stackTrace: stack);
      throw ApiException(message: 'Failed to parse conversations: $e');
    }
  }

  /// POST /messages/conversations
  Future<Conversation> startConversation(String agentProfileId) async {
    try {
      final response = await _dio.post(
        ApiConstants.conversations,
        data: {'agentProfileId': agentProfileId},
      );
      return Conversation.fromJson(
          response.data['data'] as Map<String, dynamic>);
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to start conversation',
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// POST /messages/conversations (agent → user)
  Future<Conversation> startConversationWithUser(String userId) async {
    try {
      final response = await _dio.post(
        ApiConstants.conversations,
        data: {'userId': userId},
      );
      return Conversation.fromJson(
          response.data['data'] as Map<String, dynamic>);
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to start conversation',
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// GET /messages/conversations/:id
  Future<Conversation> getConversation(String id) async {
    try {
      final response = await _dio.get('${ApiConstants.conversations}/$id');
      return Conversation.fromJson(
          response.data['data'] as Map<String, dynamic>);
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to fetch conversation',
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// GET /messages/conversations/:id/messages?page=&limit=
  Future<({List<ChatMessage> messages, PaginationInfo pagination})> getMessages(
    String conversationId, {
    int page = 1,
    int limit = 50,
  }) async {
    try {
      final response = await _dio.get(
        '${ApiConstants.conversations}/$conversationId/messages',
        queryParameters: {'page': page, 'limit': limit},
      );
      final data = response.data['data'] as Map<String, dynamic>;
      final messages = (data['messages'] as List<dynamic>)
          .map((e) => ChatMessage.fromJson(e as Map<String, dynamic>))
          .toList();
      final pagination = PaginationInfo.fromJson(
          data['pagination'] as Map<String, dynamic>);
      return (messages: messages, pagination: pagination);
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to fetch messages',
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// POST /messages/conversations/:id/messages
  Future<ChatMessage> sendMessage(
    String conversationId, {
    required String content,
    MessageType type = MessageType.text,
  }) async {
    try {
      final response = await _dio.post(
        '${ApiConstants.conversations}/$conversationId/messages',
        data: {
          'content': content,
          'messageType': type.toApiString(),
        },
      );
      return ChatMessage.fromJson(
          response.data['data'] as Map<String, dynamic>);
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to send message',
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// PATCH /messages/conversations/:id/read
  Future<void> markAsRead(String conversationId) async {
    try {
      await _dio.patch('${ApiConstants.conversations}/$conversationId/read');
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to mark as read',
        statusCode: e.response?.statusCode,
      );
    }
  }

  /// GET /messages/unread-count
  Future<int> getUnreadCount() async {
    try {
      final response = await _dio.get(ApiConstants.unreadCount);
      return response.data['data']['unreadCount'] as int? ?? 0;
    } on DioException catch (e) {
      if (e.error is ApiException) throw e.error as ApiException;
      throw ApiException(
        message: e.message ?? 'Failed to fetch unread count',
        statusCode: e.response?.statusCode,
      );
    }
  }
}

final messagingRepositoryProvider = Provider<MessagingRepository>((ref) {
  return MessagingRepository();
});
