import 'dart:convert'; import 'word_model.dart'; /// Single item in a divination reading (e.g. a drawn Rune, Card, Hexagram, or Sign) class ReadingSignItem { final String title; final String? subtitle; final String? symbol; final String? lore; final bool isReversed; final WordItem? linkedWord; final Map? meta; const ReadingSignItem({ required this.title, this.subtitle, this.symbol, this.lore, this.isReversed = false, this.linkedWord, this.meta, }); Map toMap() => { 'title': title, if (subtitle != null) 'subtitle': subtitle, if (symbol != null) 'symbol': symbol, if (lore != null) 'lore': lore, 'isReversed': isReversed, if (linkedWord != null) 'linkedWord': linkedWord!.toMap(), if (meta != null) 'meta': meta, }; factory ReadingSignItem.fromMap(Map map) => ReadingSignItem( title: map['title'] as String? ?? '', subtitle: map['subtitle'] as String?, symbol: map['symbol'] as String?, lore: map['lore'] as String?, isReversed: map['isReversed'] as bool? ?? false, linkedWord: map['linkedWord'] != null ? WordItem.fromMap(map['linkedWord'] as Map) : null, meta: map['meta'] as Map?, ); } /// A single completed divination reading inside a day session class SyncreticReading { final String id; final String systemId; // 'cleromancy', 'matrix', 'runes', 'lenormand', 'tarot', 'iching', 'ogham', 'geomancy' final String systemName; final String systemIcon; final DateTime timestamp; final String layoutTitle; // e.g. 'Бросок 2d12', 'Ленорман d6+d12', 'Триптих Норн' final String inputMethod; // 'dice' | 'manual' final List items; final String? note; final String? question; const SyncreticReading({ required this.id, required this.systemId, required this.systemName, required this.systemIcon, required this.timestamp, required this.layoutTitle, this.inputMethod = 'dice', required this.items, this.note, this.question, }); String get formattedTime { final hour = timestamp.hour.toString().padLeft(2, '0'); final min = timestamp.minute.toString().padLeft(2, '0'); return '$hour:$min'; } Map toMap() => { 'id': id, 'systemId': systemId, 'systemName': systemName, 'systemIcon': systemIcon, 'timestamp': timestamp.toIso8601String(), 'layoutTitle': layoutTitle, 'inputMethod': inputMethod, 'items': items.map((i) => i.toMap()).toList(), if (note != null) 'note': note, if (question != null) 'question': question, }; factory SyncreticReading.fromMap(Map map) => SyncreticReading( id: map['id'] as String? ?? '', systemId: map['systemId'] as String? ?? '', systemName: map['systemName'] as String? ?? '', systemIcon: map['systemIcon'] as String? ?? '🔮', timestamp: DateTime.tryParse(map['timestamp'] as String? ?? '') ?? DateTime.now(), layoutTitle: map['layoutTitle'] as String? ?? '', inputMethod: map['inputMethod'] as String? ?? 'dice', items: (map['items'] as List?) ?.map((i) => ReadingSignItem.fromMap(i as Map)) .toList() ?? [], note: map['note'] as String?, question: map['question'] as String?, ); } /// A day-long (or question-long) Syncretic Session accumulating multiple readings across systems class SyncreticSession { final String id; final DateTime date; final String? mainQuestion; final List readings; final String? comparativeAiSynthesis; const SyncreticSession({ required this.id, required this.date, this.mainQuestion, this.readings = const [], this.comparativeAiSynthesis, }); String get dateKey => '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; String get formattedDate { final day = date.day.toString().padLeft(2, '0'); final month = date.month.toString().padLeft(2, '0'); final year = date.year.toString(); return '$day.$month.$year'; } SyncreticSession copyWith({ String? id, DateTime? date, String? mainQuestion, List? readings, String? comparativeAiSynthesis, }) { return SyncreticSession( id: id ?? this.id, date: date ?? this.date, mainQuestion: mainQuestion ?? this.mainQuestion, readings: readings ?? this.readings, comparativeAiSynthesis: comparativeAiSynthesis ?? this.comparativeAiSynthesis, ); } Map toMap() => { 'id': id, 'date': date.toIso8601String(), if (mainQuestion != null) 'mainQuestion': mainQuestion, 'readings': readings.map((r) => r.toMap()).toList(), if (comparativeAiSynthesis != null) 'comparativeAiSynthesis': comparativeAiSynthesis, }; factory SyncreticSession.fromMap(Map map) => SyncreticSession( id: map['id'] as String? ?? '', date: DateTime.tryParse(map['date'] as String? ?? '') ?? DateTime.now(), mainQuestion: map['mainQuestion'] as String?, readings: (map['readings'] as List?) ?.map((r) => SyncreticReading.fromMap(r as Map)) .toList() ?? [], comparativeAiSynthesis: map['comparativeAiSynthesis'] as String?, ); String toJson() => jsonEncode(toMap()); factory SyncreticSession.fromJson(String str) => SyncreticSession.fromMap(jsonDecode(str)); }