import '../widgets/divination_instruction_modal.dart'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../models/syncretic_session_model.dart'; import '../models/tradition_model.dart'; import '../models/word_model.dart'; import '../services/traditions_repository.dart'; import '../services/words_repository.dart'; class IChingDivinationScreen extends StatefulWidget { final String? initialQuestion; const IChingDivinationScreen({super.key, this.initialQuestion}); @override State createState() => _IChingDivinationScreenState(); } class _IChingDivinationScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final _questionController = TextEditingController(); final _repo = WordsRepository(); List _hexagrams = []; // Six lines (from bottom line 1 to top line 6). Values: 6 (old yin), 7 (young yang), 8 (young yin), 9 (old yang) List _lines = []; bool _isTossingCoins = false; List _currentCoins = [3, 3, 3]; // 3 coins (2=tail, 3=head) TraditionStation? _resultStation; bool _savedToSession = false; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); if (widget.initialQuestion != null) { _questionController.text = widget.initialQuestion!; } _loadHexagrams(); } void _loadHexagrams() { final canon = TraditionsRepository().byId('iching'); if (canon != null) { _hexagrams = canon.stations; } } @override void dispose() { _tabController.dispose(); _questionController.dispose(); super.dispose(); } Future _tossCoinsStep() async { if (_lines.length >= 6) return; setState(() => _isTossingCoins = true); HapticFeedback.mediumImpact(); final rnd = Random(); for (int i = 0; i < 6; i++) { await Future.delayed(const Duration(milliseconds: 50)); if (mounted) { setState(() { _currentCoins = [ rnd.nextBool() ? 3 : 2, rnd.nextBool() ? 3 : 2, rnd.nextBool() ? 3 : 2, ]; }); } } final finalCoins = [ rnd.nextBool() ? 3 : 2, rnd.nextBool() ? 3 : 2, rnd.nextBool() ? 3 : 2, ]; final sum = finalCoins.reduce((a, b) => a + b); // 6, 7, 8, or 9 if (mounted) { setState(() { _currentCoins = finalCoins; _lines.add(sum); _isTossingCoins = false; if (_lines.length == 6) { _resolveHexagram('dice'); } }); HapticFeedback.heavyImpact(); } } void _addLineManually(int val) { if (_lines.length >= 6) return; setState(() { _lines.add(val); if (_lines.length == 6) { _resolveHexagram('manual'); } }); HapticFeedback.selectionClick(); } void _resetLines() { setState(() { _lines.clear(); _resultStation = null; _savedToSession = false; }); } void _resolveHexagram(String inputMethod) { if (_hexagrams.isEmpty || _lines.length < 6) return; // Map 6 lines to binary / trigrams // Lower trigram: lines 0, 1, 2 // Upper trigram: lines 3, 4, 5 // For now find closest matching hexagram in canon final hexIndex = (_lines.fold(0, (acc, val) => acc + val) % _hexagrams.length); final station = _hexagrams[hexIndex]; setState(() { _resultStation = station; }); _saveToSession(inputMethod); } Future _saveToSession(String inputMethod) async { if (_resultStation == null) return; final st = _resultStation!; WordItem? linkedWord; if (st.primary != null) { linkedWord = _repo.getWordById(st.primary!.id) ?? _repo.getWordByName(st.primary!.word); } final linesStr = _lines.join('-'); final item = ReadingSignItem( title: st.name, subtitle: 'Линии: $linesStr', symbol: st.symbol, lore: st.lore, linkedWord: linkedWord, ); final reading = SyncreticReading( id: 'reading_${DateTime.now().millisecondsSinceEpoch}', systemId: 'iching', systemName: 'И Цзин (Книга Перемен)', systemIcon: '☯️', timestamp: DateTime.now(), layoutTitle: '6 линий: [$linesStr]', inputMethod: inputMethod, items: [item], question: _questionController.text.trim(), ); await _repo.addReadingToSyncreticSession(reading, question: _questionController.text.trim()); if (mounted) { setState(() => _savedToSession = true); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Гексаграмма «${st.name}» добавлена в сессию дня!'), backgroundColor: const Color(0xFF2E7D32), behavior: SnackBarBehavior.floating, duration: const Duration(seconds: 2), ), ); } } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF0C0E1A), appBar: AppBar( title: const Row( children: [ Text('☯️', style: TextStyle(fontSize: 22)), SizedBox(width: 8), Text('И Цзин (3 монеты × 6)', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 17)), ], ), actions: [ IconButton( tooltip: 'Инструкция по И Цзин', icon: const Icon(Icons.help_outline_rounded, color: Color(0xFFFFD54F)), onPressed: () => DivinationInstructionModal.show(context, 'iching'), ), if (_lines.isNotEmpty) IconButton( tooltip: 'Сбросить черты', icon: const Icon(Icons.refresh_rounded), onPressed: _resetLines, ), ], bottom: TabBar( controller: _tabController, indicatorColor: const Color(0xFFFFD54F), tabs: const [ Tab(icon: Icon(Icons.toll_rounded, size: 18), text: 'Бросок 3 монет'), Tab(icon: Icon(Icons.touch_app_rounded, size: 18), text: 'Ввод черт (6..9)'), ], ), ), body: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ TextField( controller: _questionController, style: const TextStyle(color: Colors.white, fontSize: 14), decoration: InputDecoration( hintText: 'Вопрос к Книге Перемен...', hintStyle: const TextStyle(color: Color(0xFF8C93B8), fontSize: 13), prefixIcon: const Icon(Icons.help_outline_rounded, color: Color(0xFFFFD54F), size: 18), filled: true, fillColor: const Color(0xFF151829), border: OutlineInputBorder(borderRadius: BorderRadius.circular(14)), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: Color(0xFF2A2D4A)), ), ), ), const SizedBox(height: 16), // Hexagram Visualizer Box (bottom to top: line 1 at bottom, line 6 at top) _buildHexagramVisualizer(), const SizedBox(height: 16), // Controls Tabs SizedBox( height: 220, child: TabBarView( controller: _tabController, children: [ _buildCoinTossTab(), _buildManualLinesTab(), ], ), ), const SizedBox(height: 16), if (_resultStation != null) _buildResultCard(), ], ), ), ); } Widget _buildHexagramVisualizer() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF151829), borderRadius: BorderRadius.circular(20), border: Border.all(color: const Color(0xFF2A2D4A)), ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'ПОСТРОЕНИЕ ГЕКСАГРАММЫ (${_lines.length}/6)', style: const TextStyle(color: Color(0xFFFFD54F), fontSize: 11, fontWeight: FontWeight.bold), ), if (_lines.length == 6) const Text('Завершена ✓', style: TextStyle(color: Color(0xFF81C784), fontSize: 11, fontWeight: FontWeight.bold)), ], ), const SizedBox(height: 12), // Lines from top (line 6) to bottom (line 1) for (int i = 5; i >= 0; i--) Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ SizedBox( width: 28, child: Text( '${i + 1}.', style: TextStyle( color: (i < _lines.length) ? const Color(0xFFFFD54F) : const Color(0xFF5C6285), fontWeight: FontWeight.bold, fontSize: 12, ), ), ), Expanded( child: (i < _lines.length) ? _renderLineGraphic(_lines[i]) : Container( height: 8, decoration: BoxDecoration( color: const Color(0xFF1E2238), borderRadius: BorderRadius.circular(4), ), ), ), const SizedBox(width: 8), SizedBox( width: 24, child: Text( (i < _lines.length) ? '${_lines[i]}' : '', style: const TextStyle(color: Color(0xFF90A4AE), fontSize: 11, fontWeight: FontWeight.bold), ), ), ], ), ), ], ), ); } Widget _renderLineGraphic(int val) { // 7 = young yang (solid) // 9 = old yang (solid with circle/mutating) // 8 = young yin (broken) // 6 = old yin (broken with X/mutating) final isYang = (val == 7 || val == 9); final isMutating = (val == 6 || val == 9); final color = isMutating ? const Color(0xFFFF8A65) : const Color(0xFFFFD54F); if (isYang) { return Container( height: 10, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(5), ), ); } else { // Broken line return Row( children: [ Expanded( child: Container( height: 10, decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(5)), ), ), const SizedBox(width: 14), Expanded( child: Container( height: 10, decoration: BoxDecoration(color: color, borderRadius: BorderRadius.circular(5)), ), ), ], ); } } Widget _buildCoinTossTab() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF181C30), borderRadius: BorderRadius.circular(16), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ for (final c in _currentCoins) Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Container( width: 44, height: 44, alignment: Alignment.center, decoration: BoxDecoration( shape: BoxShape.circle, color: const Color(0xFF4A3E1E), border: Border.all(color: const Color(0xFFFFD54F), width: 1.5), ), child: Text( c == 3 ? 'О (3)' : 'Р (2)', style: const TextStyle(color: Color(0xFFFFF9C4), fontSize: 12, fontWeight: FontWeight.bold), ), ), ), ], ), const SizedBox(height: 16), ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFFFD54F), foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)), ), onPressed: (_lines.length >= 6 || _isTossingCoins) ? null : _tossCoinsStep, icon: const Icon(Icons.toll_rounded, size: 18), label: Text( _lines.length >= 6 ? 'Все 6 линий брошены' : (_isTossingCoins ? 'Монеты звенят...' : 'Бросить 3 монеты (линия ${_lines.length + 1})'), style: const TextStyle(fontWeight: FontWeight.bold), ), ), ], ), ); } Widget _buildManualLinesTab() { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF181C30), borderRadius: BorderRadius.circular(16), ), child: Column( children: [ Text( 'Нажмите выпавшую сумму броска со стола (${_lines.length + 1}-я черта):', style: const TextStyle(color: Color(0xFF8C93B8), fontSize: 11), ), const SizedBox(height: 12), Row( children: [ _buildManualLineButton('6 (Старая Инь ✕)', 6, Colors.redAccent), const SizedBox(width: 8), _buildManualLineButton('7 (Молодая Ян ⚊)', 7, Colors.amber), ], ), const SizedBox(height: 8), Row( children: [ _buildManualLineButton('8 (Молодая Инь ⚋)', 8, Colors.blueAccent), const SizedBox(width: 8), _buildManualLineButton('9 (Старая Ян ◯)', 9, Colors.deepOrangeAccent), ], ), ], ), ); } Widget _buildManualLineButton(String label, int val, Color color) { return Expanded( child: OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: color, side: BorderSide(color: color.withValues(alpha: 0.5)), padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), onPressed: _lines.length >= 6 ? null : () => _addLineManually(val), child: Text(label, style: const TextStyle(fontSize: 11.5, fontWeight: FontWeight.bold)), ), ); } Widget _buildResultCard() { final st = _resultStation!; return Container( padding: const EdgeInsets.all(18), decoration: BoxDecoration( color: const Color(0xFF181C30), borderRadius: BorderRadius.circular(20), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.5)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 52, height: 52, alignment: Alignment.center, decoration: BoxDecoration( color: const Color(0xFF232742), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFFFFD54F)), ), child: Text(st.symbol, style: const TextStyle(fontSize: 28, color: Color(0xFFFFD54F))), ), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(st.name, style: const TextStyle(color: Color(0xFFFFF9C4), fontSize: 16, fontWeight: FontWeight.bold)), const SizedBox(height: 4), Text(st.group, style: const TextStyle(color: Color(0xFF80DEEA), fontSize: 12)), ], ), ), ], ), const SizedBox(height: 14), const Divider(color: Color(0xFF2A2D4A)), const SizedBox(height: 10), Text(st.lore, style: const TextStyle(color: Color(0xFFE0E2EC), fontSize: 14, height: 1.5)), if (st.primary != null) ...[ const SizedBox(height: 14), Row( children: [ const Icon(Icons.link_rounded, size: 16, color: Color(0xFFFFD54F)), const SizedBox(width: 6), Text( 'Связан со знаком 999: #${st.primary!.id} «${st.primary!.word.toUpperCase()}»', style: const TextStyle(color: Color(0xFFFFD54F), fontSize: 12, fontWeight: FontWeight.bold), ), ], ), ], ], ), ); } }