package matrix

import (
	"context"
	"fmt"
	"time"
)

// ========================================
// Breakpilot Drive Game Room Types
// ========================================

// GameMode represents different multiplayer game modes
type GameMode string

const (
	GameModeSolo       GameMode = "solo"
	GameModeCoop       GameMode = "coop"       // 2 players, same track
	GameModeChallenge  GameMode = "challenge"  // 1v1 competition
	GameModeClassRace  GameMode = "class_race" // Whole class competition
)

// GameRoomConfig holds configuration for game rooms
type GameRoomConfig struct {
	GameMode     GameMode `json:"game_mode"`
	SessionID    string   `json:"session_id"`
	HostUserID   string   `json:"host_user_id"`
	HostName     string   `json:"host_name"`
	ClassName    string   `json:"class_name,omitempty"`
	MaxPlayers   int      `json:"max_players,omitempty"`
	TeacherIDs   []string `json:"teacher_ids,omitempty"`
	EnableVoice  bool     `json:"enable_voice,omitempty"`
}

// GameRoom represents an active game room
type GameRoom struct {
	RoomID       string    `json:"room_id"`
	SessionID    string    `json:"session_id"`
	GameMode     GameMode  `json:"game_mode"`
	HostUserID   string    `json:"host_user_id"`
	Players      []string  `json:"players"`
	CreatedAt    time.Time `json:"created_at"`
	IsActive     bool      `json:"is_active"`
}

// GameEvent represents game events to broadcast
type GameEvent struct {
	Type      string      `json:"type"`
	SessionID string      `json:"session_id"`
	PlayerID  string      `json:"player_id"`
	Data      interface{} `json:"data"`
	Timestamp time.Time   `json:"timestamp"`
}

// GameEventType constants
const (
	GameEventPlayerJoined   = "player_joined"
	GameEventPlayerLeft     = "player_left"
	GameEventGameStarted    = "game_started"
	GameEventQuizAnswered   = "quiz_answered"
	GameEventScoreUpdate    = "score_update"
	GameEventAchievement    = "achievement"
	GameEventChallengeWon   = "challenge_won"
	GameEventRaceFinished   = "race_finished"
)

// ========================================
// Game Room Management
// ========================================

// CreateGameTeamRoom creates a private room for 2-4 players (Co-Op mode)
func (s *MatrixService) CreateGameTeamRoom(ctx context.Context, config GameRoomConfig) (*CreateRoomResponse, error) {
	roomName := fmt.Sprintf("Breakpilot Drive - Team %s", config.SessionID[:8])
	topic := "Co-Op Spielsession - Arbeitet zusammen!"

	// All players can write
	users := make(map[string]int)
	users[s.GenerateUserID(config.HostUserID)] = 50

	req := CreateRoomRequest{
		Name:       roomName,
		Topic:      topic,
		Visibility: "private",
		Preset:     "private_chat",
		InitialState: []StateEvent{
			{
				Type:     "m.room.encryption",
				StateKey: "",
				Content: map[string]string{
					"algorithm": "m.megolm.v1.aes-sha2",
				},
			},
			// Custom game state
			{
				Type:     "breakpilot.game.session",
				StateKey: "",
				Content: map[string]interface{}{
					"session_id": config.SessionID,
					"game_mode":  string(config.GameMode),
					"host_id":    config.HostUserID,
					"created_at": time.Now().UTC().Format(time.RFC3339),
				},
			},
		},
		PowerLevelContentOverride: &PowerLevels{
			EventsDefault: 0, // All players can send messages
			UsersDefault:  50,
			Users:         users,
			Events: map[string]int{
				"breakpilot.game.event": 0, // Anyone can send game events
			},
		},
	}

	return s.CreateRoom(ctx, req)
}

// CreateGameChallengeRoom creates a 1v1 challenge room
func (s *MatrixService) CreateGameChallengeRoom(ctx context.Context, config GameRoomConfig, challengerID string, opponentID string) (*CreateRoomResponse, error) {
	roomName := fmt.Sprintf("Challenge: %s", config.SessionID[:8])
	topic := "1v1 Wettbewerb - Möge der Bessere gewinnen!"

	allPlayers := []string{
		s.GenerateUserID(challengerID),
		s.GenerateUserID(opponentID),
	}

	users := make(map[string]int)
	for _, id := range allPlayers {
		users[id] = 50
	}

	req := CreateRoomRequest{
		Name:       roomName,
		Topic:      topic,
		Visibility: "private",
		Preset:     "private_chat",
		Invite:     allPlayers,
		InitialState: []StateEvent{
			{
				Type:     "breakpilot.game.session",
				StateKey: "",
				Content: map[string]interface{}{
					"session_id":    config.SessionID,
					"game_mode":     string(GameModeChallenge),
					"challenger_id": challengerID,
					"opponent_id":   opponentID,
					"created_at":    time.Now().UTC().Format(time.RFC3339),
				},
			},
		},
		PowerLevelContentOverride: &PowerLevels{
			EventsDefault: 0,
			UsersDefault:  50,
			Users:         users,
		},
	}

	return s.CreateRoom(ctx, req)
}

// CreateGameClassRaceRoom creates a room for class-wide competition
func (s *MatrixService) CreateGameClassRaceRoom(ctx context.Context, config GameRoomConfig) (*CreateRoomResponse, error) {
	roomName := fmt.Sprintf("Klassenrennen: %s", config.ClassName)
	topic := fmt.Sprintf("Klassenrennen der %s - Alle gegen alle!", config.ClassName)

	// Teachers get moderator power level
	users := make(map[string]int)
	for _, teacherID := range config.TeacherIDs {
		users[s.GenerateUserID(teacherID)] = 100
	}

	req := CreateRoomRequest{
		Name:       roomName,
		Topic:      topic,
		Visibility: "private",
		Preset:     "private_chat",
		InitialState: []StateEvent{
			{
				Type:     "breakpilot.game.session",
				StateKey: "",
				Content: map[string]interface{}{
					"session_id":  config.SessionID,
					"game_mode":   string(GameModeClassRace),
					"class_name":  config.ClassName,
					"teacher_ids": config.TeacherIDs,
					"created_at":  time.Now().UTC().Format(time.RFC3339),
				},
			},
		},
		PowerLevelContentOverride: &PowerLevels{
			EventsDefault: 0,  // Students can send messages
			UsersDefault:  10, // Default student level
			Users:         users,
			Invite:        100, // Only teachers can invite
			Kick:          100, // Only teachers can kick
			Events: map[string]int{
				"breakpilot.game.event":      0,   // Anyone can send game events
				"breakpilot.game.leaderboard": 100, // Only teachers update leaderboard
			},
		},
	}

	return s.CreateRoom(ctx, req)
}

// ========================================
// Game Event Broadcasting
// ========================================

// SendGameEvent sends a game event to a room
func (s *MatrixService) SendGameEvent(ctx context.Context, roomID string, event GameEvent) error {
	event.Timestamp = time.Now().UTC()

	return s.sendEvent(ctx, roomID, "breakpilot.game.event", event)
}

// SendPlayerJoinedEvent notifies room that a player joined
func (s *MatrixService) SendPlayerJoinedEvent(ctx context.Context, roomID string, sessionID string, playerID string, playerName string) error {
	event := GameEvent{
		Type:      GameEventPlayerJoined,
		SessionID: sessionID,
		PlayerID:  playerID,
		Data: map[string]string{
			"player_name": playerName,
		},
	}

	// Also send a visible message
	msg := fmt.Sprintf("🎮 %s ist dem Spiel beigetreten!", playerName)
	if err := s.SendMessage(ctx, roomID, msg); err != nil {
		// Log but don't fail
		fmt.Printf("Warning: failed to send join message: %v\n", err)
	}

	return s.SendGameEvent(ctx, roomID, event)
}

// SendScoreUpdateEvent broadcasts score updates
func (s *MatrixService) SendScoreUpdateEvent(ctx context.Context, roomID string, sessionID string, playerID string, score int, accuracy float64) error {
	event := GameEvent{
		Type:      GameEventScoreUpdate,
		SessionID: sessionID,
		PlayerID:  playerID,
		Data: map[string]interface{}{
			"score":    score,
			"accuracy": accuracy,
		},
	}

	return s.SendGameEvent(ctx, roomID, event)
}

// SendQuizAnsweredEvent broadcasts when a player answers a quiz
func (s *MatrixService) SendQuizAnsweredEvent(ctx context.Context, roomID string, sessionID string, playerID string, correct bool, subject string) error {
	event := GameEvent{
		Type:      GameEventQuizAnswered,
		SessionID: sessionID,
		PlayerID:  playerID,
		Data: map[string]interface{}{
			"correct": correct,
			"subject": subject,
		},
	}

	return s.SendGameEvent(ctx, roomID, event)
}

// SendAchievementEvent broadcasts when a player earns an achievement
func (s *MatrixService) SendAchievementEvent(ctx context.Context, roomID string, sessionID string, playerID string, achievementID string, achievementName string) error {
	event := GameEvent{
		Type:      GameEventAchievement,
		SessionID: sessionID,
		PlayerID:  playerID,
		Data: map[string]interface{}{
			"achievement_id":   achievementID,
			"achievement_name": achievementName,
		},
	}

	// Also send a visible celebration message
	msg := fmt.Sprintf("🏆 Erfolg freigeschaltet: %s!", achievementName)
	if err := s.SendMessage(ctx, roomID, msg); err != nil {
		fmt.Printf("Warning: failed to send achievement message: %v\n", err)
	}

	return s.SendGameEvent(ctx, roomID, event)
}

// SendChallengeWonEvent broadcasts challenge result
func (s *MatrixService) SendChallengeWonEvent(ctx context.Context, roomID string, sessionID string, winnerID string, winnerName string, loserName string, winnerScore int, loserScore int) error {
	event := GameEvent{
		Type:      GameEventChallengeWon,
		SessionID: sessionID,
		PlayerID:  winnerID,
		Data: map[string]interface{}{
			"winner_name":  winnerName,
			"loser_name":   loserName,
			"winner_score": winnerScore,
			"loser_score":  loserScore,
		},
	}

	// Send celebration message
	msg := fmt.Sprintf("🎉 %s gewinnt gegen %s mit %d zu %d Punkten!", winnerName, loserName, winnerScore, loserScore)
	if err := s.SendHTMLMessage(ctx, roomID, msg, fmt.Sprintf("<h3>🎉 Challenge beendet!</h3><p><strong>%s</strong> gewinnt gegen %s</p><p>Endstand: %d : %d</p>", winnerName, loserName, winnerScore, loserScore)); err != nil {
		fmt.Printf("Warning: failed to send challenge result message: %v\n", err)
	}

	return s.SendGameEvent(ctx, roomID, event)
}

// SendClassRaceLeaderboard broadcasts current leaderboard in class race
func (s *MatrixService) SendClassRaceLeaderboard(ctx context.Context, roomID string, sessionID string, leaderboard []map[string]interface{}) error {
	// Build leaderboard message
	msg := "🏁 Aktueller Stand:\n"
	htmlMsg := "<h3>🏁 Aktueller Stand</h3><ol>"

	for i, entry := range leaderboard {
		if i >= 10 { // Top 10 only
			break
		}
		name := entry["name"].(string)
		score := entry["score"].(int)
		msg += fmt.Sprintf("%d. %s - %d Punkte\n", i+1, name, score)
		htmlMsg += fmt.Sprintf("<li><strong>%s</strong> - %d Punkte</li>", name, score)
	}
	htmlMsg += "</ol>"

	return s.SendHTMLMessage(ctx, roomID, msg, htmlMsg)
}

// ========================================
// Game Room Utilities
// ========================================

// AddPlayerToGameRoom invites and sets up a player in a game room
func (s *MatrixService) AddPlayerToGameRoom(ctx context.Context, roomID string, playerMatrixID string, playerName string) error {
	// Invite the player
	if err := s.InviteUser(ctx, roomID, playerMatrixID); err != nil {
		return fmt.Errorf("failed to invite player: %w", err)
	}

	// Set display name if not already set
	if err := s.SetDisplayName(ctx, playerMatrixID, playerName); err != nil {
		// Log but don't fail - display name might already be set
		fmt.Printf("Warning: failed to set display name: %v\n", err)
	}

	return nil
}

// CloseGameRoom sends end message and archives the room
func (s *MatrixService) CloseGameRoom(ctx context.Context, roomID string, sessionID string) error {
	// Send closing message
	msg := "🏁 Spiel beendet! Danke fürs Mitspielen. Dieser Raum wird archiviert."
	if err := s.SendMessage(ctx, roomID, msg); err != nil {
		return fmt.Errorf("failed to send closing message: %w", err)
	}

	// Update room state to mark as closed
	closeEvent := map[string]interface{}{
		"closed":    true,
		"closed_at": time.Now().UTC().Format(time.RFC3339),
	}

	return s.sendEvent(ctx, roomID, "breakpilot.game.closed", closeEvent)
}
