import { useState, useEffect } from 'react' import { useParams, useNavigate } from 'react-router-dom' import { marathonsApi, gamesApi } from '@/api' import type { Marathon, Game, Challenge, ChallengePreview } from '@/types' import { Button, Input, Card, CardContent, CardHeader, CardTitle } from '@/components/ui' import { useAuthStore } from '@/store/auth' import { Plus, Trash2, Sparkles, Play, Loader2, Gamepad2, X, Save, Eye, ChevronDown, ChevronUp, Edit2, Check } from 'lucide-react' export function LobbyPage() { const { id } = useParams<{ id: string }>() const navigate = useNavigate() const user = useAuthStore((state) => state.user) const [marathon, setMarathon] = useState(null) const [games, setGames] = useState([]) const [isLoading, setIsLoading] = useState(true) // Add game form const [showAddGame, setShowAddGame] = useState(false) const [gameTitle, setGameTitle] = useState('') const [gameUrl, setGameUrl] = useState('') const [gameGenre, setGameGenre] = useState('') const [isAddingGame, setIsAddingGame] = useState(false) // Generate challenges const [isGenerating, setIsGenerating] = useState(false) const [generateMessage, setGenerateMessage] = useState(null) const [previewChallenges, setPreviewChallenges] = useState(null) const [isSaving, setIsSaving] = useState(false) const [editingIndex, setEditingIndex] = useState(null) // View existing challenges const [expandedGameId, setExpandedGameId] = useState(null) const [gameChallenges, setGameChallenges] = useState>({}) const [loadingChallenges, setLoadingChallenges] = useState(null) // Start marathon const [isStarting, setIsStarting] = useState(false) useEffect(() => { loadData() }, [id]) const loadData = async () => { if (!id) return try { const [marathonData, gamesData] = await Promise.all([ marathonsApi.get(parseInt(id)), gamesApi.list(parseInt(id)), ]) setMarathon(marathonData) setGames(gamesData) } catch (error) { console.error('Failed to load data:', error) navigate('/marathons') } finally { setIsLoading(false) } } const handleAddGame = async () => { if (!id || !gameTitle.trim() || !gameUrl.trim()) return setIsAddingGame(true) try { await gamesApi.create(parseInt(id), { title: gameTitle.trim(), download_url: gameUrl.trim(), genre: gameGenre.trim() || undefined, }) setGameTitle('') setGameUrl('') setGameGenre('') setShowAddGame(false) await loadData() } catch (error) { console.error('Failed to add game:', error) } finally { setIsAddingGame(false) } } const handleDeleteGame = async (gameId: number) => { if (!confirm('Удалить эту игру?')) return try { await gamesApi.delete(gameId) await loadData() } catch (error) { console.error('Failed to delete game:', error) } } const handleToggleGameChallenges = async (gameId: number) => { if (expandedGameId === gameId) { setExpandedGameId(null) return } setExpandedGameId(gameId) if (!gameChallenges[gameId]) { setLoadingChallenges(gameId) try { const challenges = await gamesApi.getChallenges(gameId) setGameChallenges(prev => ({ ...prev, [gameId]: challenges })) } catch (error) { console.error('Failed to load challenges:', error) } finally { setLoadingChallenges(null) } } } const handleDeleteChallenge = async (challengeId: number, gameId: number) => { if (!confirm('Удалить это задание?')) return try { await gamesApi.deleteChallenge(challengeId) // Refresh challenges for this game const challenges = await gamesApi.getChallenges(gameId) setGameChallenges(prev => ({ ...prev, [gameId]: challenges })) await loadData() // Refresh game counts } catch (error) { console.error('Failed to delete challenge:', error) } } const handleGenerateChallenges = async () => { if (!id) return setIsGenerating(true) setGenerateMessage(null) try { const result = await gamesApi.previewChallenges(parseInt(id)) if (result.challenges.length === 0) { setGenerateMessage('Все игры уже имеют задания') } else { setPreviewChallenges(result.challenges) } } catch (error) { console.error('Failed to generate challenges:', error) setGenerateMessage('Не удалось сгенерировать задания') } finally { setIsGenerating(false) } } const handleSaveChallenges = async () => { if (!id || !previewChallenges) return setIsSaving(true) try { const result = await gamesApi.saveChallenges(parseInt(id), previewChallenges) setGenerateMessage(result.message) setPreviewChallenges(null) setGameChallenges({}) // Clear cache to reload await loadData() } catch (error) { console.error('Failed to save challenges:', error) setGenerateMessage('Не удалось сохранить задания') } finally { setIsSaving(false) } } const handleRemovePreviewChallenge = (index: number) => { if (!previewChallenges) return setPreviewChallenges(previewChallenges.filter((_, i) => i !== index)) if (editingIndex === index) setEditingIndex(null) } const handleUpdatePreviewChallenge = (index: number, field: keyof ChallengePreview, value: string | number) => { if (!previewChallenges) return setPreviewChallenges(previewChallenges.map((ch, i) => i === index ? { ...ch, [field]: value } : ch )) } const handleCancelPreview = () => { setPreviewChallenges(null) setEditingIndex(null) } const handleStartMarathon = async () => { if (!id || !confirm('Начать марафон? После этого нельзя будет добавить новые игры.')) return setIsStarting(true) try { await marathonsApi.start(parseInt(id)) navigate(`/marathons/${id}/play`) } catch (err: unknown) { const error = err as { response?: { data?: { detail?: string } } } alert(error.response?.data?.detail || 'Не удалось запустить марафон') } finally { setIsStarting(false) } } if (isLoading || !marathon) { return (
) } const isOrganizer = user?.id === marathon.organizer.id const totalChallenges = games.reduce((sum, g) => sum + g.challenges_count, 0) return (

{marathon.title}

Настройка - Добавьте игры и сгенерируйте задания

{isOrganizer && ( )}
{/* Stats */}
{games.length}
Игр
{totalChallenges}
Заданий
{/* Generate challenges button */} {games.length > 0 && !previewChallenges && (

Генерация заданий

Используйте ИИ для генерации заданий для всех игр без заданий

{generateMessage && (

{generateMessage}

)}
)} {/* Challenge preview with editing */} {previewChallenges && previewChallenges.length > 0 && (
Предпросмотр заданий ({previewChallenges.length})
{previewChallenges.map((challenge, index) => (
{editingIndex === index ? ( // Edit mode
{challenge.game_title}
handleUpdatePreviewChallenge(index, 'title', e.target.value)} placeholder="Название" className="bg-gray-800" />