import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import '../utils/logger.dart';

/// Service for managing conversation history in Firestore
/// Structure: userChats/{userId}/conversations/{conversationId}/messages/{messageId}
class ChatMemoryService {
  static final FirebaseFirestore _firestore = FirebaseFirestore.instance;
  static final FirebaseAuth _auth = FirebaseAuth.instance;

  /// Current active conversation ID
  static String? _currentConversationId;

  /// Get current conversation ID
  static String? get currentConversationId => _currentConversationId;

  /// Set current conversation ID
  static void setCurrentConversationId(String? id) {
    _currentConversationId = id;
  }

  /// Create a new conversation
  static Future<String> createConversation({
    required List<String> selectedMaterialIds,
    String? title,
  }) async {
    final user = _auth.currentUser;
    if (user == null) {
      throw Exception('User not authenticated');
    }

    final conversationRef = await _firestore
        .collection('userChats')
        .doc(user.uid)
        .collection('conversations')
        .add({
          'title': title ?? 'Nova conversa',
          'createdAt': FieldValue.serverTimestamp(),
          'updatedAt': FieldValue.serverTimestamp(),
          'selectedMaterialIds': selectedMaterialIds,
          'messageCount': 0,
          'hasUserMessage': false,
        });

    _currentConversationId = conversationRef.id;
    Logger.info('Created new conversation: ${conversationRef.id}');
    return conversationRef.id;
  }

  /// Update conversation materials
  static Future<void> updateConversationMaterials({
    required String conversationId,
    required List<String> selectedMaterialIds,
  }) async {
    try {
      await _firestore
          .collection('userChats')
          .doc(_auth.currentUser?.uid)
          .collection('conversations')
          .doc(conversationId)
          .update({
            'selectedMaterialIds': selectedMaterialIds,
            'updatedAt': FieldValue.serverTimestamp(),
          });
      Logger.info('Updated materials for conversation: $conversationId');
    } catch (e) {
      Logger.error('Error updating conversation materials: $e');
    }
  }

  /// Update conversation title
  static Future<void> updateConversationTitle({
    required String conversationId,
    required String title,
  }) async {
    try {
      await _firestore
          .collection('userChats')
          .doc(_auth.currentUser?.uid)
          .collection('conversations')
          .doc(conversationId)
          .update({'title': title, 'updatedAt': FieldValue.serverTimestamp()});
      Logger.info('Updated title for conversation: $conversationId');
    } catch (e) {
      Logger.error('Error updating conversation title: $e');
    }
  }

  /// Get all conversations for current user
  static Future<List<Map<String, dynamic>>> getConversations() async {
    try {
      final user = _auth.currentUser;
      if (user == null) return [];

      final snapshot = await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .orderBy('updatedAt', descending: true)
          .get();

      final conversations = snapshot.docs
          .map((doc) {
            final data = doc.data();
            return {
              'id': doc.id,
              'title': data['title'] as String? ?? 'Sem título',
              'createdAt': data['createdAt'] as Timestamp?,
              'updatedAt': data['updatedAt'] as Timestamp?,
              'selectedMaterialIds':
                  (data['selectedMaterialIds'] as List<dynamic>?)
                      ?.cast<String>() ??
                  [],
              'messageCount': data['messageCount'] as int? ?? 0,
              'hasUserMessage': data['hasUserMessage'] as bool? ?? false,
            };
          })
          .where((conv) => (conv['hasUserMessage'] as bool) == true)
          .toList();

      Logger.info('Retrieved ${conversations.length} conversations');
      return conversations;
    } catch (e) {
      Logger.error('Error getting conversations: $e');
      return [];
    }
  }

  /// Delete a conversation
  static Future<void> deleteConversation(String conversationId) async {
    try {
      final user = _auth.currentUser;
      if (user == null) return;

      // Delete all messages in the conversation
      final messagesSnapshot = await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(conversationId)
          .collection('messages')
          .get();

      final batch = _firestore.batch();
      for (final doc in messagesSnapshot.docs) {
        batch.delete(doc.reference);
      }

      // Delete the conversation document
      batch.delete(
        _firestore
            .collection('userChats')
            .doc(user.uid)
            .collection('conversations')
            .doc(conversationId),
      );

      await batch.commit();

      if (_currentConversationId == conversationId) {
        _currentConversationId = null;
      }

      Logger.info('Deleted conversation: $conversationId');
    } catch (e) {
      Logger.error('Error deleting conversation: $e');
    }
  }

  /// Save a message to Firestore
  static Future<void> saveMessage({
    required String role, // 'user' or 'assistant'
    required String content,
    String? conversationId,
  }) async {
    try {
      final user = _auth.currentUser;
      if (user == null) return;

      final convId = conversationId ?? _currentConversationId;
      if (convId == null) {
        Logger.warning('No conversation ID, message not saved');
        return;
      }

      final messageData = {
        'role': role,
        'content': content,
        'createdAt': FieldValue.serverTimestamp(),
        'userId': user.uid,
      };

      await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(convId)
          .collection('messages')
          .add(messageData);

      // Update conversation metadata
      final updateData = <String, dynamic>{
        'updatedAt': FieldValue.serverTimestamp(),
        'messageCount': FieldValue.increment(1),
      };

      // Set hasUserMessage to true if this is a user message
      if (role == 'user') {
        updateData['hasUserMessage'] = true;
      }

      await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(convId)
          .update(updateData);

      Logger.info(
        'Message saved to Firestore: role=$role, conversation=$convId',
      );
    } catch (e) {
      Logger.error('Error saving message: $e');
    }
  }

  /// Get the last N messages from a specific conversation
  /// Returns list of messages sorted by createdAt ascending (oldest first)
  static Future<List<Map<String, dynamic>>> getConversationMessages({
    required String conversationId,
    int limit = 20,
  }) async {
    try {
      final user = _auth.currentUser;
      if (user == null) return [];

      final snapshot = await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(conversationId)
          .collection('messages')
          .orderBy('createdAt', descending: true)
          .limit(limit)
          .get();

      // Convert to list and reverse to get ascending order (oldest first)
      final messages = snapshot.docs
          .map(
            (doc) => {
              'role': doc.data()['role'] as String,
              'content': doc.data()['content'] as String,
              'createdAt': doc.data()['createdAt'] as Timestamp?,
            },
          )
          .toList()
          .reversed
          .toList();

      Logger.info(
        'Retrieved ${messages.length} messages from conversation $conversationId',
      );
      return messages;
    } catch (e) {
      Logger.error('Error getting conversation messages: $e');
      return [];
    }
  }

  /// Get conversation details
  static Future<Map<String, dynamic>?> getConversation(
    String conversationId,
  ) async {
    try {
      final user = _auth.currentUser;
      if (user == null) return null;

      final doc = await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(conversationId)
          .get();

      if (!doc.exists) return null;

      final data = doc.data();
      return {
        'id': doc.id,
        'title': data?['title'] as String? ?? 'Sem título',
        'createdAt': data?['createdAt'] as Timestamp?,
        'updatedAt': data?['updatedAt'] as Timestamp?,
        'selectedMaterialIds':
            (data?['selectedMaterialIds'] as List<dynamic>?)?.cast<String>() ??
            [],
        'messageCount': data?['messageCount'] as int? ?? 0,
        'hasUserMessage': data?['hasUserMessage'] as bool? ?? false,
      };
    } catch (e) {
      Logger.error('Error getting conversation: $e');
      return null;
    }
  }

  /// Build messages array for API request from current conversation
  /// Returns list of message maps with 'role' and 'content' keys
  static Future<List<Map<String, String>>> buildMessagesForAPI({
    required String currentUserMessage,
    String? conversationId,
    int historyLimit = 20,
  }) async {
    final messages = <Map<String, String>>[];

    final convId = conversationId ?? _currentConversationId;
    if (convId != null) {
      // Get recent conversation history
      final history = await getConversationMessages(
        conversationId: convId,
        limit: historyLimit,
      );

      // Add historical messages
      for (final msg in history) {
        messages.add({
          'role': msg['role'] as String,
          'content': msg['content'] as String,
        });
      }
    }

    // Add current user message
    messages.add({'role': 'user', 'content': currentUserMessage});

    Logger.info(
      'Built messages array with ${messages.length} messages for API',
    );
    return messages;
  }

  /// Clear current conversation history
  static Future<void> clearHistory() async {
    try {
      final user = _auth.currentUser;
      if (user == null) return;

      final convId = _currentConversationId;
      if (convId == null) return;

      final snapshot = await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(convId)
          .collection('messages')
          .get();

      // Delete all messages in batches
      final batch = _firestore.batch();
      for (final doc in snapshot.docs) {
        batch.delete(doc.reference);
      }
      await batch.commit();

      // Reset message count
      await _firestore
          .collection('userChats')
          .doc(user.uid)
          .collection('conversations')
          .doc(convId)
          .update({'messageCount': 0});

      Logger.info('Conversation history cleared');
    } catch (e) {
      Logger.error('Error clearing history: $e');
    }
  }

  /// Generate a smart title from the first message by extracting keywords
  static String generateConversationTitle(String firstMessage) {
    // Remove common Portuguese stopwords and greetings
    final stopwords = {
      'olá',
      'oi',
      'bom dia',
      'boa tarde',
      'boa noite',
      'consegues',
      'podes',
      'pode',
      'poderia',
      'poderias',
      'explicar',
      'explica',
      'explicar-me',
      'explicar-lhe',
      'sobre',
      'acerca de',
      'a respeito de',
      'relativamente a',
      'o que é',
      'o que são',
      'qual é',
      'quais são',
      'como',
      'onde',
      'quando',
      'porquê',
      'por que',
      'quero',
      'quero que',
      'gostaria',
      'gostaria de',
      'preciso',
      'preciso de',
      'ajuda',
      'ajuda-me',
      'me',
      'te',
      'lhe',
      'nos',
      'vos',
      'um',
      'uma',
      'uns',
      'umas',
      'e',
      'ou',
      'mas',
      'porém',
      'todavia',
      'para',
      'de',
      'em',
      'a',
      'o',
      'as',
      'os',
      'que',
      'quem',
      'qual',
      'quais',
      'é',
      'são',
      'está',
      'estão',
      'foi',
      'foram',
      '?',
      '!',
      '.',
      ',',
      ';',
      ':',
    };

    // Convert to lowercase and remove punctuation
    final cleaned = firstMessage
        .toLowerCase()
        .replaceAll(RegExp(r'[?!.;,]'), '')
        .trim();

    // Split into words and remove stopwords
    final words = cleaned
        .split(' ')
        .where((word) => word.isNotEmpty && !stopwords.contains(word))
        .toList();

    // Take the first 2-3 meaningful words as the title
    if (words.isEmpty) {
      return firstMessage.length > 30
          ? '${firstMessage.substring(0, 30)}...'
          : firstMessage;
    }

    final titleWords = words.take(3).join(' ');
    // Capitalize first letter of each word
    final title = titleWords
        .split(' ')
        .map((word) {
          if (word.isEmpty) return '';
          return word[0].toUpperCase() + word.substring(1);
        })
        .join(' ');

    return title.length > 40 ? '${title.substring(0, 40)}...' : title;
  }
}
