import 'package:flutter/foundation.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; import 'package:sqflite/sqflite.dart'; import '../models/message_model.dart'; /// Local cache of messages keyed by context + room (plan: 맥락 ID 반영). /// On **web**, uses in-memory storage only (`sqflite` is not supported). class MessageLocalStore { MessageLocalStore(); Database? _db; /// Web-only: key = "contextId::roomId" final Map> _memory = {}; static String _memKey(String contextId, String roomId) => '$contextId::$roomId'; Future get database async { if (kIsWeb) { throw UnsupportedError('database getter should not be used on web'); } if (_db != null) return _db!; final dir = await getApplicationDocumentsDirectory(); final path = p.join(dir.path, 'msn_messages.db'); _db = await openDatabase( path, version: 1, onCreate: (db, v) async { await db.execute(''' CREATE TABLE messages ( id TEXT NOT NULL, context_id TEXT NOT NULL, room_id TEXT NOT NULL, sender_id TEXT NOT NULL, body TEXT NOT NULL, created_at TEXT NOT NULL, kind TEXT NOT NULL DEFAULT 'text', PRIMARY KEY (id, context_id) ); '''); await db.execute( 'CREATE INDEX idx_room_ctx ON messages(room_id, context_id, created_at);', ); }, ); return _db!; } /// [roomId] required so empty API results can clear the web cache. Future upsertMessages( String contextId, String roomId, List list, ) async { if (kIsWeb) { final key = _memKey(contextId, roomId); if (list.isEmpty) { _memory[key] = []; return; } final byId = { for (final m in _memory[key] ?? []) m.id: m, }; for (final m in list) { byId[m.id] = m; } final merged = byId.values.toList() ..sort((a, b) => a.createdAt.compareTo(b.createdAt)); _memory[key] = merged; return; } final db = await database; final batch = db.batch(); for (final m in list) { batch.insert( 'messages', { 'id': m.id, 'context_id': contextId, 'room_id': m.roomId, 'sender_id': m.senderId, 'body': m.body, 'created_at': m.createdAt, 'kind': m.kind, }, conflictAlgorithm: ConflictAlgorithm.replace, ); } await batch.commit(noResult: true); } Future> listForRoom(String contextId, String roomId) async { if (kIsWeb) { return List.from(_memory[_memKey(contextId, roomId)] ?? []); } final db = await database; final rows = await db.query( 'messages', where: 'context_id = ? AND room_id = ?', whereArgs: [contextId, roomId], orderBy: 'created_at ASC', ); return rows .map( (r) => MessageModel( id: r['id']! as String, roomId: r['room_id']! as String, senderId: r['sender_id']! as String, body: r['body']! as String, createdAt: r['created_at']! as String, kind: r['kind'] as String? ?? 'text', ), ) .toList(); } }