import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../models/history_entry_model.dart'; import '../models/houses_session_model.dart'; import '../models/word_model.dart'; import '../services/ai_oracle_service.dart'; import '../widgets/gradient_star_badge.dart'; import 'symbol_detail_screen.dart'; import 'matrix_geometry_screen.dart'; import '../models/syncretic_session_model.dart'; import '../services/words_repository.dart'; class HouseChainsScreen extends StatefulWidget { final HousesSession session; const HouseChainsScreen({super.key, required this.session}); @override State createState() => _HouseChainsScreenState(); } class _HouseChainsScreenState extends State { final _aiService = AiOracleService(); final Map _chainAiInterpretations = {}; final Set _loadingChains = {}; @override void initState() { super.initState(); _recordChainsToSyncreticSession(showToast: false); } Future _recordChainsToSyncreticSession({bool showToast = false}) async { final session = widget.session; if (session.chains.isEmpty) return; final chainItems = session.chains.map((chain) { final pathStr = chain.steps.map((s) => '«${s.guest.word.toUpperCase()}»').join(' ➔ '); final startWord = chain.startingHouse.houseWord; final aiText = _chainAiInterpretations[chain.chainIndex]; var loreText = 'Траектория: ' + pathStr + '\n' + chain.description; if (aiText != null && aiText.isNotEmpty) { loreText += '\n\nТолкование Оракула:\n' + aiText; } return ReadingSignItem( title: 'Цепочка #${chain.chainIndex}: ${chain.endTypeTitle}', subtitle: 'Старт: Дом #${chain.startingHouse.houseIndex + 1} «${startWord.word}» • Шагов: ${chain.steps.length}', symbol: chain.hasLoop ? '🔄' : (chain.endType == ChainEndType.archonThrone ? '👑' : '🔗'), lore: loreText, linkedWord: chain.steps.isNotEmpty ? chain.steps.last.guest : startWord, meta: { 'chainIndex': chain.chainIndex, 'endType': chain.endType.name, 'stepsCount': chain.steps.length, 'path': pathStr, }, ); }).toList(); await WordsRepository().addReadingToSyncreticSession( SyncreticReading( id: 'chains_${session.id}', systemId: 'matrix_chains', systemName: 'Матрица 33×30: Цепочки Домов', systemIcon: '🔗', timestamp: session.createdAt, layoutTitle: '${session.chains.length} ${session.chains.length == 1 ? "цепочка" : (session.chains.length < 5 ? "цепочки" : "цепочек")}', inputMethod: 'dice', items: chainItems, question: session.question, ), question: session.question, ); if (showToast && mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Цепочки домов (${session.chains.length}) сохранены в Синхроническую сессию дня', style: const TextStyle(fontWeight: FontWeight.w600), ), backgroundColor: const Color(0xFF1E2238), behavior: SnackBarBehavior.floating, ), ); } } Future _interpretChain(HouseChain chain) async { setState(() => _loadingChains.add(chain.chainIndex)); HapticFeedback.lightImpact(); final buffer = StringBuffer(); buffer.writeln('Ты — верховный оракул, читающий цепочки домов Ленорман в системе Оракула 999.'); buffer.writeln('Проанализируй путь перетекания силы в цепочке домов:'); buffer.writeln('ЦЕПОЧКА #${chain.chainIndex} (${chain.steps.length} шагов).'); buffer.writeln('ИТОГ ЦЕПОЧКИ: ${chain.description}.\n'); for (int i = 0; i < chain.steps.length; i++) { final step = chain.steps[i]; final sector = widget.session.sectors[step.house.sectorIndex]; buffer.writeln( 'Шаг ${i + 1}: В Доме #${step.house.houseIndex + 1} «${step.house.houseWord.word.toUpperCase()}» (Архонт «${sector.archonWord.word.toUpperCase()}») выпал Гость «${step.guest.word.toUpperCase()}».', ); if (step.isLoopClosing) { buffer.writeln(' ➔ [ПЕТЛЯ ЗАМКНУЛАСЬ: возврат энергии в исходный дом]'); } else if (step.leadsToArchon) { buffer.writeln(' ➔ [ВОСХОЖДЕНИЕ К АРХОНТУ: увенчание Престолом «${step.destinationArchon?.archonWord.word.toUpperCase()}»]'); } else if (step.computed) { buffer.writeln(' ➔ [ВЫЧИСЛЕНО ИЗ ПОЛЯ, НЕ ЖРЕБИЙ: дом не был открыт]'); } } buffer.writeln('\nДай емкое и глубокое толкование: что запускает этот поток, где ключевой перелом и к какому исходу приводит замыкание цепи.'); try { final res = await _aiService.interpretSession( words: chain.steps .map((s) => SessionWord.fromWordItem( s.guest, positionTitle: 'Дом «${s.house.houseWord.word}»', )) .toList(), question: widget.session.question ?? 'Цепочка домов судьбы', ); if (mounted) { setState(() { _chainAiInterpretations[chain.chainIndex] = res; _loadingChains.remove(chain.chainIndex); }); _recordChainsToSyncreticSession(showToast: false); } } catch (e) { if (mounted) { setState(() { _chainAiInterpretations[chain.chainIndex] = 'Связь с оракулом прервалась: $e'; _loadingChains.remove(chain.chainIndex); }); } } } void _openWordDossier(WordItem word) { HapticFeedback.selectionClick(); Navigator.push( context, MaterialPageRoute(builder: (context) => SymbolDetailScreen(word: word)), ); } void _copyChain(HouseChain chain) { final buffer = StringBuffer(); buffer.writeln('🔗 ОРАКУЛ — ЦЕПОЧКА ДОМОВ #${chain.chainIndex}'); buffer.writeln('Итог: ${chain.description}\n'); for (int i = 0; i < chain.steps.length; i++) { final s = chain.steps[i]; final archon = widget.session.sectors[s.house.sectorIndex].archonWord.word.toUpperCase(); buffer.writeln( '${i + 1}. [Архонт: $archon] ➔ Дом «${s.house.houseWord.word.toUpperCase()}» ➔ Гость «${s.guest.word.toUpperCase()}»', ); if (s.isLoopClosing) { buffer.writeln(' 🔄 Цикл замкнулся!'); } else if (s.leadsToArchon) { buffer.writeln(' 👑 Восхождение к Архонту «${s.destinationArchon?.archonWord.word.toUpperCase()}»'); } else if (s.computed) { buffer.writeln(' ◎ Знак вычислен из поля, это не жребий.'); } } if (_chainAiInterpretations[chain.chainIndex] != null) { buffer.writeln('\n🤖 Толкование Оракула:\n${_chainAiInterpretations[chain.chainIndex]}'); } Clipboard.setData(ClipboardData(text: buffer.toString())); HapticFeedback.selectionClick(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Цепочка домов скопирована в буфер'), behavior: SnackBarBehavior.floating, ), ); } @override Widget build(BuildContext context) { final chains = widget.session.chains; return Scaffold( backgroundColor: const Color(0xFF0A0C16), appBar: AppBar( title: const Row( children: [ GradientStar(size: 20), SizedBox(width: 8), Text('Цепочки Домов', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)), ], ), actions: [ IconButton( tooltip: 'Записать цепочки в Синхроническую сессию дня', icon: const Icon(Icons.bookmark_add_rounded, color: Color(0xFFFFD54F)), onPressed: () => _recordChainsToSyncreticSession(showToast: true), ), ], ), body: chains.isEmpty ? const Center( child: Text( 'В данном раскладе нет открытых цепочек', style: TextStyle(color: Color(0xFFB0BEC5)), ), ) : ListView.builder( padding: const EdgeInsets.fromLTRB(16, 12, 16, 40), itemCount: chains.length + 1, itemBuilder: (context, index) { if (index == 0) { return _buildHeaderInfo(); } final chain = chains[index - 1]; return _buildChainCard(chain); }, ), ); } Widget _buildHeaderInfo() { return Container( margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF151829), borderRadius: BorderRadius.circular(18), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.3)), ), child: const Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(Icons.hub_outlined, color: Color(0xFFFFD54F), size: 24), SizedBox(width: 12), Expanded( child: Text( 'Цепочки домов показывают траекторию судьбы: гость из первого дома ведет в собственную обитель на поле 33×30, гость следующего дома ведет дальше — пока энергия не замкнется в петлю судьбы или не взойдет к Престолу Архонта.', style: TextStyle(color: Color(0xFFCFD8DC), fontSize: 13, height: 1.45), ), ), ], ), ); } Widget _buildChainCard(HouseChain chain) { final isInterpreting = _loadingChains.contains(chain.chainIndex); final aiText = _chainAiInterpretations[chain.chainIndex]; Color statusColor; IconData statusIcon; String statusTitle; switch (chain.endType) { case ChainEndType.loop: statusColor = const Color(0xFFE57373); statusIcon = Icons.sync_rounded; statusTitle = 'Петля Судьбы (Замкнутый узел)'; break; case ChainEndType.archonThrone: statusColor = const Color(0xFFFFD54F); statusIcon = Icons.shield_rounded; statusTitle = 'Восхождение к Престолу Архонта'; break; case ChainEndType.fieldVector: statusColor = const Color(0xFF64B5F6); statusIcon = Icons.trending_flat_rounded; statusTitle = 'Вектор в поле (Открытый луч)'; break; } return Container( margin: const EdgeInsets.only(bottom: 20), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF131627), borderRadius: BorderRadius.circular(22), border: Border.all( color: chain.hasLoop ? const Color(0xFFFFD54F).withValues(alpha: 0.5) : const Color(0xFF2A2D4A), width: chain.hasLoop ? 1.5 : 1.0, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header: Chain index + Status Badge Row( children: [ Text( 'ЦЕПОЧКА #${chain.chainIndex}', style: const TextStyle( color: Color(0xFFFFD54F), fontWeight: FontWeight.w900, fontSize: 16, letterSpacing: 0.8, ), ), const Spacer(), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: statusColor.withValues(alpha: 0.18), borderRadius: BorderRadius.circular(8), border: Border.all(color: statusColor, width: 1.0), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(statusIcon, size: 14, color: statusColor), const SizedBox(width: 4), Text( statusTitle, style: TextStyle( color: statusColor, fontSize: 11, fontWeight: FontWeight.bold, ), ), ], ), ), ], ), const SizedBox(height: 6), Text( chain.description, style: const TextStyle(color: Color(0xFFB0BEC5), fontSize: 12), ), const SizedBox(height: 16), // Steps list for (int i = 0; i < chain.steps.length; i++) ...[ _buildStepRow(chain.steps[i], i + 1), if (i < chain.steps.length - 1) Padding( padding: const EdgeInsets.only(left: 20, top: 4, bottom: 4), child: Row( children: [ const Icon(Icons.arrow_downward_rounded, size: 16, color: Color(0xFFFFD54F)), const SizedBox(width: 8), Text( 'переход в обитель знака «${chain.steps[i].guest.word.toUpperCase()}» на поле', style: const TextStyle(color: Color(0xFF78909C), fontSize: 10, fontStyle: FontStyle.italic), ), ], ), ), ], const SizedBox(height: 16), // AI Interpretation if exists if (aiText != null) ...[ Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: const Color(0xFF1E2238), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.4)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.auto_awesome_rounded, color: Color(0xFFFFD54F), size: 16), SizedBox(width: 6), Text( 'Толкование цепочки Оракулом:', style: TextStyle( color: Color(0xFFFFD54F), fontWeight: FontWeight.bold, fontSize: 13, ), ), ], ), const SizedBox(height: 8), Text( aiText, style: const TextStyle(color: Color(0xFFECEFF1), fontSize: 13, height: 1.45), ), ], ), ), const SizedBox(height: 12), ], // Action Buttons Row( children: [ ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2A2D4A), foregroundColor: const Color(0xFFFFD54F), padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: const BorderSide(color: Color(0xFFFFD54F), width: 0.8), ), ), onPressed: isInterpreting ? null : () => _interpretChain(chain), icon: isInterpreting ? const SizedBox( width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2, color: Color(0xFFFFD54F)), ) : const Icon(Icons.auto_awesome, size: 16), label: Text( aiText == null ? 'Трактовать (AI)' : 'Обновить (AI)', style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold), ), ), const SizedBox(width: 8), OutlinedButton.icon( style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF), width: 0.8), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), ), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => MatrixGeometryScreen( session: widget.session, initialChainIndex: chain.chainIndex, ), ), ); }, icon: const Icon(Icons.polyline_rounded, size: 15), label: const Text('Узор на поле', style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold)), ), const Spacer(), IconButton( tooltip: 'Скопировать цепочку', icon: const Icon(Icons.copy_rounded, size: 18, color: Color(0xFF9FA8DA)), onPressed: () => _copyChain(chain), ), ], ), ], ), ); } Widget _buildStepRow(HouseChainStep step, int order) { final sector = widget.session.sectors[step.house.sectorIndex]; return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: const Color(0xFF181C33), borderRadius: BorderRadius.circular(14), border: Border.all( color: step.isLoopClosing ? const Color(0xFFE57373) : (step.leadsToArchon ? const Color(0xFFFFD54F) : sector.sectorColor.withValues(alpha: 0.3)), width: (step.isLoopClosing || step.leadsToArchon) ? 1.5 : 1.0, ), ), child: Row( children: [ // Order circle Container( width: 24, height: 24, decoration: BoxDecoration( color: sector.sectorColor.withValues(alpha: 0.2), shape: BoxShape.circle, border: Border.all(color: sector.sectorColor), ), child: Center( child: Text( '$order', style: TextStyle( color: sector.sectorColor, fontWeight: FontWeight.w900, fontSize: 11, ), ), ), ), const SizedBox(width: 12), // Content Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // House title InkWell( onTap: () => _openWordDossier(step.house.houseWord), child: Row( children: [ Text( 'Дом #${(step.house.houseIndex + 1).toString().padLeft(3, '0')}: «${step.house.houseWord.word.toUpperCase()}»', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.w900, fontSize: 13, ), ), const SizedBox(width: 6), Text( '(Архонт: ${sector.archonWord.word})', style: TextStyle( color: sector.sectorColor, fontSize: 11, fontWeight: FontWeight.w600, ), ), ], ), ), const SizedBox(height: 3), // Guest title InkWell( onTap: () => _openWordDossier(step.guest), child: Row( children: [ const Icon(Icons.auto_awesome_rounded, size: 13, color: Color(0xFFFFD54F)), const SizedBox(width: 4), Text( step.computed ? 'Вычислен из поля, не жребий: «${step.guest.word.toUpperCase()}»' : 'В него пришел Гость: «${step.guest.word.toUpperCase()}»', style: const TextStyle( color: Color(0xFFFFD54F), fontSize: 12, fontWeight: FontWeight.bold, ), ), ], ), ), // Special termination notices if (step.isLoopClosing) ...[ const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFFE57373).withValues(alpha: 0.2), borderRadius: BorderRadius.circular(6), ), child: const Row( mainAxisSize: MainAxisSize.min, children: [ Icon(Icons.sync_rounded, size: 12, color: Color(0xFFE57373)), SizedBox(width: 4), Text( '🔄 Узел замкнулся: энергия возвращается в исходный дом!', style: TextStyle(color: Color(0xFFEF9A9A), fontSize: 11, fontWeight: FontWeight.bold), ), ], ), ), ] else if (step.leadsToArchon) ...[ const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFFFFD54F).withValues(alpha: 0.2), borderRadius: BorderRadius.circular(6), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.shield_rounded, size: 12, color: Color(0xFFFFD54F)), const SizedBox(width: 4), Text( '👑 Восхождение к Престолу Архонта «${step.destinationArchon?.archonWord.word.toUpperCase()}»!', style: const TextStyle(color: Color(0xFFFFF9C4), fontSize: 11, fontWeight: FontWeight.bold), ), ], ), ), ], ], ), ), ], ), ); } }