import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'dart:math'; import '../../models/participant_model.dart'; import '../../models/team_model.dart'; import '../../services/event_service.dart'; import '../../widgets/loading_indicator.dart'; import '../../widgets/dialog_actions.dart'; class TeamGeneratorScreen extends StatefulWidget { final String eventId; final List participants; final List? existingTeams; const TeamGeneratorScreen({ Key? key, required this.eventId, required this.participants, this.existingTeams, }) : super(key: key); @override State createState() => _TeamGeneratorScreenState(); } class _TeamGeneratorScreenState extends State { bool _isLoading = false; int _teamCount = 2; bool _balanceTeams = true; List _generatedTeams = []; final _formKey = GlobalKey(); // 참가자 선택 상태 관리 final Map _selectedParticipants = {}; @override void initState() { super.initState(); // 모든 참가자 기본 선택 for (var participant in widget.participants) { if (participant.status == '참석함' || participant.status == '확인됨') { _selectedParticipants[participant.memberId] = true; } else { _selectedParticipants[participant.memberId] = false; } } // 기존 팀이 있으면 팀 수 설정 if (widget.existingTeams != null && widget.existingTeams!.isNotEmpty) { _teamCount = widget.existingTeams!.length; _generatedTeams = List.from(widget.existingTeams!); } } // 팀 생성 void _generateTeams() { if (!_formKey.currentState!.validate()) { return; } // 선택된 참가자 목록 생성 final selectedParticipants = widget.participants .where((p) => _selectedParticipants[p.memberId] == true) .toList(); if (selectedParticipants.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('최소 한 명 이상의 참가자를 선택해주세요')), ); return; } if (_teamCount <= 0 || _teamCount > selectedParticipants.length) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('유효한 팀 수를 입력해주세요')), ); return; } setState(() { _isLoading = true; }); try { // 참가자 섞기 final shuffledParticipants = List.from(selectedParticipants)..shuffle(); // 팀 생성 final teams = List.generate(_teamCount, (index) => []); if (_balanceTeams) { // 균등하게 팀 배분 for (int i = 0; i < shuffledParticipants.length; i++) { teams[i % _teamCount].add(shuffledParticipants[i]); } } else { // 랜덤 배분 final random = Random(); for (var participant in shuffledParticipants) { teams[random.nextInt(_teamCount)].add(participant); } } // Team 객체로 변환 _generatedTeams = List.generate( _teamCount, (index) => Team( id: widget.existingTeams != null && index < widget.existingTeams!.length ? widget.existingTeams![index].id : '', eventId: widget.eventId, name: '${index + 1}', memberIds: teams[index].map((p) => p.memberId).toList(), description: '자동 생성된 팀', ), ); setState(() { _isLoading = false; }); } catch (e) { setState(() { _isLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('팀 생성 중 오류가 발생했습니다: $e')), ); } } // 팀 저장 Future _saveTeams() async { if (_generatedTeams.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('먼저 팀을 생성해주세요')), ); return; } setState(() { _isLoading = true; }); try { final eventService = Provider.of(context, listen: false); // 팀 저장 (서비스는 List을 기대함) await eventService.saveTeams(widget.eventId, _generatedTeams); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('팀이 저장되었습니다')), ); Navigator.of(context).pop(true); // 성공 결과와 함께 이전 화면으로 돌아가기 } } catch (e) { if (mounted) { setState(() { _isLoading = false; }); ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('팀 저장에 실패했습니다: $e')), ); } } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('팀 생성'), actions: [ if (_generatedTeams.isNotEmpty) IconButton( icon: const Icon(Icons.save), onPressed: _saveTeams, ), ], ), body: _isLoading ? const LoadingIndicator() : SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 팀 생성 설정 섹션 _buildSectionTitle('팀 생성 설정'), // 팀 수 설정 TextFormField( initialValue: _teamCount.toString(), decoration: const InputDecoration( labelText: '팀 수', hintText: '생성할 팀 수를 입력하세요', ), keyboardType: TextInputType.number, validator: (value) { if (value == null || value.isEmpty) { return '팀 수를 입력해주세요'; } final teamCount = int.tryParse(value); if (teamCount == null || teamCount <= 0) { return '유효한 팀 수를 입력해주세요'; } return null; }, onChanged: (value) { setState(() { _teamCount = int.tryParse(value) ?? 2; }); }, ), const SizedBox(height: 16), // 균등 배분 설정 SwitchListTile( title: const Text('균등하게 팀 배분'), subtitle: const Text('참가자를 팀에 균등하게 배분합니다'), value: _balanceTeams, onChanged: (value) { setState(() { _balanceTeams = value; }); }, ), const SizedBox(height: 16), // 팀 생성 버튼 SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _generateTeams, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), ), child: const Text( '팀 생성하기', style: TextStyle(fontSize: 16), ), ), ), const SizedBox(height: 24), // 참가자 선택 섹션 _buildSectionTitle('참가자 선택'), // 전체 선택/해제 버튼 Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () { setState(() { for (var key in _selectedParticipants.keys) { _selectedParticipants[key] = true; } }); }, child: const Text('전체 선택'), ), const SizedBox(width: 8), TextButton( onPressed: () { setState(() { for (var key in _selectedParticipants.keys) { _selectedParticipants[key] = false; } }); }, child: const Text('전체 해제'), ), ], ), const SizedBox(height: 8), // 참가자 목록 ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: widget.participants.length, itemBuilder: (context, index) { final participant = widget.participants[index]; return CheckboxListTile( title: Text(participant.name ?? '이름 없음'), subtitle: Text(participant.status ?? '상태 없음'), value: _selectedParticipants[participant.memberId] ?? false, onChanged: (value) { setState(() { _selectedParticipants[participant.memberId] = value ?? false; }); }, ); }, ), if (_generatedTeams.isNotEmpty) ...[ const SizedBox(height: 24), // 생성된 팀 섹션 _buildSectionTitle('생성된 팀'), // 팀 목록 ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _generatedTeams.length, itemBuilder: (context, teamIndex) { final team = _generatedTeams[teamIndex]; // 팀원 목록 생성 final teamMembers = widget.participants .where((p) => team.memberIds.contains(p.memberId)) .toList(); return Card( margin: const EdgeInsets.only(bottom: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( title: Text( '팀 ${team.name}', style: const TextStyle( fontWeight: FontWeight.bold, ), ), subtitle: Text('${teamMembers.length}명'), trailing: IconButton( icon: const Icon(Icons.edit), onPressed: () { // 팀 이름 수정 다이얼로그 showDialog( context: context, builder: (context) { String newName = team.name; return AlertDialog( title: const Text('팀 이름 수정'), content: TextField( autofocus: true, decoration: const InputDecoration( labelText: '팀 이름', ), onChanged: (value) { newName = value; }, controller: TextEditingController(text: team.name), ), actions: DialogActions.confirm( onCancel: () => Navigator.of(context).pop(), onConfirm: () { setState(() { _generatedTeams[teamIndex] = Team( id: team.id, eventId: team.eventId, name: newName, memberIds: team.memberIds, description: team.description, ); }); Navigator.of(context).pop(); }, confirmText: '저장', ), ); }, ); }, ), ), const Divider(), ...teamMembers.map((member) => ListTile( leading: const Icon(Icons.person), title: Text(member.name ?? '이름 없음'), trailing: IconButton( icon: const Icon(Icons.swap_horiz), onPressed: () { // 팀원 이동 다이얼로그 showDialog( context: context, builder: (context) { int targetTeamIndex = teamIndex; return AlertDialog( title: const Text('팀원 이동'), content: DropdownButton( value: targetTeamIndex, items: List.generate( _generatedTeams.length, (index) => DropdownMenuItem( value: index, child: Text('팀 ${_generatedTeams[index].name}'), ), ), onChanged: (value) { if (value != null) { targetTeamIndex = value; } }, ), actions: DialogActions.confirm( onCancel: () => Navigator.of(context).pop(), onConfirm: () { if (targetTeamIndex != teamIndex) { setState(() { _generatedTeams[teamIndex] = Team( id: team.id, eventId: team.eventId, name: team.name, memberIds: team.memberIds .where((id) => id != member.memberId) .toList(), description: team.description, ); final targetTeam = _generatedTeams[targetTeamIndex]; _generatedTeams[targetTeamIndex] = Team( id: targetTeam.id, eventId: targetTeam.eventId, name: targetTeam.name, memberIds: [ ...targetTeam.memberIds, member.memberId, ], description: targetTeam.description, ); }); } Navigator.of(context).pop(); }, confirmText: '이동', ), ); }, ); }, ), )), ], ), ); }, ), // 팀 저장 버튼 const SizedBox(height: 16), SizedBox( width: double.infinity, child: ElevatedButton( onPressed: _saveTeams, style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: Colors.green, ), child: const Text( '팀 저장하기', style: TextStyle(fontSize: 16), ), ), ), ], ], ), ), ), ); } // 섹션 제목 위젯 Widget _buildSectionTitle(String title) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, ), ), const Divider(), const SizedBox(height: 8), ], ); } }