import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../core/api_client.dart';
import '../../data/message_model.dart';
import '../../core/hive_service.dart';

final chatRepositoryProvider =
    Provider((ref) => ChatRepository(ref.read(apiClientProvider)));

class ChatRepository {
  final ApiClient _apiClient;
  String lastUrl = ""; // For debug

  ChatRepository(this._apiClient);

  Future<List<Conversation>> getConversations() async {
    lastUrl = _apiClient.client.options.baseUrl + '/conversations';
    final response = await _apiClient.client.get('/conversations');
    final data = response.data is List ? response.data : response.data['data'];
    return (data as List).map((e) => Conversation.fromJson(e)).toList();
  }

  Future<List<Message>> getMessages(int conversationId, {int? cursor, String? token}) async {
    lastUrl = _apiClient.client.options.baseUrl + '/conversations/$conversationId/messages';
    // 1. Try to load from cache first if cursor is null (initial load)
    if (cursor == null) {
      final cachedJson = HiveService.messageBox.get('conv_$conversationId');
      if (cachedJson != null) {
        try {
          final List<dynamic> decoded = jsonDecode(cachedJson);
          return decoded.map((e) => Message.fromJson(e)).toList();
        } catch (e) {
          // Fallback to network
        }
      }
    }

    // 2. Network call
    final response = await _apiClient.client.get(
        '/conversations/$conversationId/messages',
        queryParameters: {if (cursor != null) 'cursor': cursor},
        options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null
    );
    final data = response.data is List ? response.data : response.data['data'];
    final messages = (data as List).map((e) => Message.fromJson(e)).toList();

    // 3. Cache latest messages (if initial load)
    if (cursor == null && messages.isNotEmpty) {
      // Store as JSON
      HiveService.messageBox.put('conv_$conversationId', jsonEncode(data));
    }

    return messages;
  }

  Future<List<Message>> getMessagesSince(
      int conversationId, int afterId, {String? token}) async {
    final response = await _apiClient.client.get('/messages/since',
        queryParameters: {
          'conversation_id': conversationId,
          'after_id': afterId
        },
        options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null
    );
    final data = response.data is List ? response.data : response.data['data'];
    final newMessages = (data as List).map((e) => Message.fromJson(e)).toList();

    // Update cache if we have new messages
    if (newMessages.isNotEmpty) {
      final cachedJson = HiveService.messageBox.get('conv_$conversationId');
      List<dynamic> cachedList = [];
      if (cachedJson != null) {
         cachedList = jsonDecode(cachedJson);
      }
      
      // Append new messages to cache
      // We need to avoid duplicates. Since newMessages are "since" afterId, they should be new.
      // But let's be safe.
      final existingIds = cachedList.map((e) => e['id']).toSet();
      for (var item in data) {
         if (!existingIds.contains(item['id'])) {
            cachedList.add(item);
         }
      }
      
      // Limit cache size per conversation (e.g. last 100 messages)
      if (cachedList.length > 100) {
        cachedList = cachedList.sublist(cachedList.length - 100);
      }

      HiveService.messageBox.put('conv_$conversationId', jsonEncode(cachedList));
    }

    return newMessages;
  }

  Future<Map<String, dynamic>> sendMessage(int conversationId, String text, {int? recipientId, String? token}) async {
    lastUrl = _apiClient.client.options.baseUrl + '/messages/send';
    final data = <String, dynamic>{'body_text': text};
    if (conversationId > 0) {
      data['conversation_id'] = conversationId;
    }
    // Always send recipient_id if available, to allow recovery from invalid conversation_id
    if (recipientId != null) {
      data['recipient_id'] = recipientId;
    }
    final response = await _apiClient.client.post('/messages/send', 
      data: data,
      options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null
    );
    return response.data;
  }

  Future<void> markAsRead(int conversationId) async {
    await _apiClient.client.post('/messages/read',
        data: {'conversation_id': conversationId});
  }

  Future<void> createReport({
    required int reportedUserId,
    required int conversationId,
    required String reason,
    String? token,
  }) async {
    await _apiClient.client.post(
      '/reports',
      data: {
        'reported_user_id': reportedUserId,
        'conversation_id': conversationId,
        'reason': reason,
      },
      options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null,
    );
  }

  Future<Map<String, dynamic>> toggleBlock({
    required int targetId,
    required int conversationId,
    String? token,
  }) async {
    final response = await _apiClient.client.post(
      '/blocks/toggle',
      data: {
        'target_id': targetId,
        'conversation_id': conversationId,
      },
      options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null,
    );
    return response.data is Map<String, dynamic> ? response.data : <String, dynamic>{};
  }

  Future<bool> getBlockStatus({
    required int targetId,
    required int conversationId,
    String? token,
  }) async {
    final response = await _apiClient.client.post(
      '/blocks/status',
      data: {
        'target_id': targetId,
        'conversation_id': conversationId,
      },
      options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null,
    );
    final data = response.data;
    if (data is Map && data['blocked'] != null) return data['blocked'] == true;
    return false;
  }

  Future<void> clearConversation(int conversationId, {String? token}) async {
    await _apiClient.client.post(
      '/conversations/$conversationId/clear',
      options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null,
    );
  }

  Future<void> clearConversationCache(int conversationId) async {
    await HiveService.messageBox.delete('conv_$conversationId');
  }

  Future<void> clearAllChatHistory({String? token}) async {
    await _apiClient.client.post(
      '/conversations/clear_all',
      options: token != null ? Options(headers: {'Authorization': 'Bearer $token'}) : null,
    );
  }

  Future<void> clearAllConversationCaches() async {
    await HiveService.messageBox.clear();
  }

  Future<Map<String, dynamic>> startAnonChat(
      String slug, String visitorHash) async {
    final response = await _apiClient.client.post('/anon/start',
        data: {'owner_slug': slug, 'visitor_hash': visitorHash});
    return response.data;
  }
}
