import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; import '../services/firebase_service.dart'; // ── Model ────────────────────────────────────────────────────────────────── class AmorChatEntry { final String text; final bool isUser; final DateTime time; AmorChatEntry({ required this.text, required this.isUser, required this.time, }); Map toJson() => { 'text': text, 'isUser': isUser, 'time': time.toIso8601String(), }; factory AmorChatEntry.fromJson(Map json) => AmorChatEntry( text: json['text'] as String, isUser: json['isUser'] as bool, time: DateTime.parse(json['time'] as String), ); } // ── State ────────────────────────────────────────────────────────────────── class AmorChatState { final List messages; final bool isLoading; final bool isLoadedFromFirestore; const AmorChatState({ this.messages = const [], this.isLoading = false, this.isLoadedFromFirestore = false, }); AmorChatState copyWith({ List? messages, bool? isLoading, bool? isLoadedFromFirestore, }) => AmorChatState( messages: messages ?? this.messages, isLoading: isLoading ?? this.isLoading, isLoadedFromFirestore: isLoadedFromFirestore ?? this.isLoadedFromFirestore, ); } // ── Notifier ─────────────────────────────────────────────────────────────── class AmorChatNotifier extends StateNotifier { final FirebaseFirestore _db = FirebaseFirestore.instance; static const String _chatCollection = 'amorChatHistory'; static const int _maxMessages = 100; // batas simpan AmorChatNotifier() : super(const AmorChatState()); String? get _uid => FirebaseService().currentUser?.uid; // ── Load riwayat dari Firestore ────────────────────────────────────────── Future loadHistory() async { if (state.isLoadedFromFirestore) return; // sudah dimuat, skip final uid = _uid; if (uid == null) return; try { final doc = await _db.collection(_chatCollection).doc(uid).get(); if (doc.exists && doc.data() != null) { final raw = doc.data()!['messages'] as List? ?? []; final msgs = raw .map((e) => AmorChatEntry.fromJson(Map.from(e as Map))) .toList(); state = state.copyWith( messages: msgs, isLoadedFromFirestore: true, ); } else { state = state.copyWith(isLoadedFromFirestore: true); } } catch (e) { debugPrint('AmorChat loadHistory error: $e'); state = state.copyWith(isLoadedFromFirestore: true); } } // ── Tambah pesan user ──────────────────────────────────────────────────── void addUserMessage(String text) { final entry = AmorChatEntry( text: text, isUser: true, time: DateTime.now(), ); state = state.copyWith(messages: [...state.messages, entry]); } // ── Tambah pesan AI & simpan ke Firestore ──────────────────────────────── Future addAIMessage(String text) async { final entry = AmorChatEntry( text: text, isUser: false, time: DateTime.now(), ); final updated = [...state.messages, entry]; state = state.copyWith(messages: updated); await _saveToFirestore(updated); } // ── Set loading ────────────────────────────────────────────────────────── void setLoading(bool v) => state = state.copyWith(isLoading: v); // ── Hapus semua riwayat ────────────────────────────────────────────────── Future clearHistory() async { state = state.copyWith(messages: []); final uid = _uid; if (uid == null) return; try { await _db.collection(_chatCollection).doc(uid).delete(); } catch (e) { debugPrint('AmorChat clearHistory error: $e'); } } // ── Simpan ke Firestore ────────────────────────────────────────────────── Future _saveToFirestore(List messages) async { final uid = _uid; if (uid == null) return; try { // Batasi ke _maxMessages terakhir agar tidak membengkak final limited = messages.length > _maxMessages ? messages.sublist(messages.length - _maxMessages) : messages; await _db.collection(_chatCollection).doc(uid).set({ 'messages': limited.map((m) => m.toJson()).toList(), 'updatedAt': DateTime.now().toIso8601String(), }); } catch (e) { debugPrint('AmorChat _saveToFirestore error: $e'); } } // Kembalikan history dalam format yang dibutuhkan GeminiService List> get aiHistory => state.messages .map((m) => { 'role': m.isUser ? 'user' : 'model', 'text': m.text, }) .toList(); } // ── Provider ─────────────────────────────────────────────────────────────── final amorChatProvider = StateNotifierProvider( (ref) => AmorChatNotifier(), );