// controllers/tournamentController.js
import tournamentService from "../services/tournamentService.js";
import { emitTournamentChanged } from '../services/socketService.js';
import TournamentClass from '../models/TournamentClass.js';
import HttpError from '../exceptions/HttpError.js';

// 1. Alle Turniere eines Vereins
export const getTournaments = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId } = req.params;
    try {
        const tournaments = await tournamentService.getTournaments(token, clubId);
        res.status(200).json(tournaments);
    } catch (error) {
        console.error(error);
        if (error instanceof HttpError) {
            res.set('x-debug-tournament-clubid', String(clubId));
            res.set('x-debug-tournament-clubid-num', String(Number(clubId)));
            return res.status(error.statusCode || 500).json({ error: error.message });
        }
        res.status(500).json({ error: error.message });
    }
};

// 2. Neues Turnier anlegen
export const addTournament = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentName, date, winningSets, allowsExternal } = req.body;
    try {
        const tournament = await tournamentService.addTournament(token, clubId, tournamentName, date, winningSets, allowsExternal);
        // Emit Socket-Event
        if (clubId && tournament && tournament.id) {
            emitTournamentChanged(clubId, tournament.id);
        }
        res.status(201).json(tournament);
    } catch (error) {
        console.error('[addTournament] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// 3. Teilnehmer hinzufügen - klassengebunden
export const addParticipant = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, classId, participant: participantId, tournamentId } = req.body;
    try {
    // Payloads:
    // - Mit Klasse (klassengebunden): { clubId, classId, participant }
    // - Ohne Klasse (turnierweit):    { clubId, tournamentId, participant, classId: null }
        if (!participantId) {
            return res.status(400).json({ error: 'Teilnehmer-ID ist erforderlich' });
        }
        // Allow adding a participant either to a specific class (classId) or to the whole tournament (no class)
        if (!classId && !tournamentId) {
            return res.status(400).json({ error: 'Klasse oder tournamentId ist erforderlich' });
        }

        // Pass through to service. If classId is present it will be used, otherwise the service should add the participant with classId = null for the given tournamentId
        await tournamentService.addParticipant(token, clubId, classId || null, participantId, tournamentId || null);

        // Determine tournamentId for response and event emission
        let respTournamentId = tournamentId;
        if (classId && !respTournamentId) {
            const tournamentClass = await TournamentClass.findByPk(classId);
            if (!tournamentClass) {
                return res.status(404).json({ error: 'Klasse nicht gefunden' });
            }
            respTournamentId = tournamentClass.tournamentId;
        }

        // Fetch updated participants for the (optional) class or whole tournament
        const participants = await tournamentService.getParticipants(token, clubId, respTournamentId, classId || null);
        // Emit Socket-Event
        if (respTournamentId) emitTournamentChanged(clubId, respTournamentId);
        res.status(200).json(participants);
    } catch (error) {
        console.error('[addParticipant] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// 4. Teilnehmerliste abrufen - nach Klasse oder Turnier
export const getParticipants = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.body;
    try {
        const participants = await tournamentService.getParticipants(token, clubId, tournamentId, classId || null);
        res.status(200).json(participants);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 5. Turniermodus (Gruppen/K.O.) setzen
export const setModus = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, type, numberOfGroups, advancingPerGroup } = req.body;
    try {
        await tournamentService.setModus(token, clubId, tournamentId, type, numberOfGroups, advancingPerGroup);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.sendStatus(204);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 6. Gruppen-Strukturen anlegen (leere Gruppen)
export const createGroups = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, numberOfGroups } = req.body;
    try {
        // DEBUG: Eingehende Daten sichtbar machen (temporär)
        console.log('[tournamentController.createGroups] body:', req.body);
        console.log('[tournamentController.createGroups] types:', {
            clubId: typeof clubId,
            tournamentId: typeof tournamentId,
            numberOfGroups: typeof numberOfGroups,
        });

        // Turniere ohne Klassen: `numberOfGroups: 0` kommt aus der UI (Default) vor.
        // Statt „nichts passiert“ normalisieren wir auf mindestens 1 Gruppe.
        let normalizedNumberOfGroups = numberOfGroups;
        if (normalizedNumberOfGroups !== undefined && normalizedNumberOfGroups !== null) {
            const n = Number(normalizedNumberOfGroups);
            console.log('[tournamentController.createGroups] parsed numberOfGroups:', n);
            if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0) {
                return res.status(400).json({ error: 'numberOfGroups muss eine ganze Zahl >= 0 sein' });
            }
            normalizedNumberOfGroups = Math.max(1, n);
        }

        console.log('[tournamentController.createGroups] normalizedNumberOfGroups:', normalizedNumberOfGroups);

        await tournamentService.createGroups(token, clubId, tournamentId, normalizedNumberOfGroups);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.sendStatus(204);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 6b. Gruppen-Strukturen pro Klasse anlegen
export const createGroupsPerClass = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, groupsPerClass } = req.body;
    try {
        await tournamentService.createGroupsPerClass(token, clubId, tournamentId, groupsPerClass);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.sendStatus(204);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 7. Teilnehmer zufällig auf Gruppen verteilen & Gruppenspiele anlegen
export const fillGroups = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.body;
    try {
        const updatedMembers = await tournamentService.fillGroups(token, clubId, tournamentId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(updatedMembers);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 7b. Gruppenspiele erstellen ohne Gruppenzuordnungen zu ändern
export const createGroupMatches = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.body;
    try {
        await tournamentService.createGroupMatches(token, clubId, tournamentId, classId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.sendStatus(204);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 8. Gruppen mit ihren Teilnehmern abfragen
export const getGroups = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.query;
    try {
        const groups = await tournamentService.getGroupsWithParticipants(token, clubId, tournamentId);
        res.status(200).json(groups);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 9. Einzelnes Turnier abrufen
export const getTournament = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.params;
    try {
        const tournament = await tournamentService.getTournament(token, clubId, tournamentId);
        res.status(200).json(tournament);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// Update Turnier
export const updateTournament = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.params;
    const { name, date, winningSets, numberOfTables } = req.body;
    try {
        // Debug: log incoming payload for troubleshooting Android client
        console.log('[updateTournament] incoming body:', req.body);
        const tournament = await tournamentService.updateTournament(token, clubId, tournamentId, name, date, winningSets, numberOfTables);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(tournament);
    } catch (error) {
        console.error('[updateTournament] Error:', error);
        const status = error.message.includes('existiert bereits') ? 400 : 500;
        res.status(status).json({ error: error.message });
    }
};

// 10. Alle Spiele eines Turniers abfragen
export const getTournamentMatches = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.params;
    try {
        const matches = await tournamentService.getTournamentMatches(token, clubId, tournamentId);
        res.status(200).json(matches);
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// Setze Tischnummer für ein Spiel
export const setMatchTable = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, matchId } = req.params;
    const { tableNumber } = req.body;
    try {
        const updated = await tournamentService.setMatchTable(token, clubId, tournamentId, matchId, tableNumber);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(updated);
    } catch (error) {
        console.error('[setMatchTable] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// Freie Tische verteilen (Batch)
export const distributeTables = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.body;
    try {
        const updated = await tournamentService.distributeTables(token, clubId, tournamentId);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ updated, message: 'Tische wurden verteilt.' });
    } catch (error) {
        console.error('[distributeTables] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// 11. Satz-Ergebnis speichern
export const addMatchResult = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, matchId, set, result } = req.body;
    try {
        await tournamentService.addMatchResult(token, clubId, tournamentId, matchId, set, result);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: "Result added successfully" });
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

// 12. Spiel abschließen (Endergebnis ermitteln)
export const finishMatch = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, matchId } = req.body;
    try {
        await tournamentService.finishMatch(token, clubId, tournamentId, matchId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: "Match finished successfully" });
    } catch (error) {
        console.error(error);
        res.status(500).json({ error: error.message });
    }
};

export const startKnockout = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.body;

    try {
        await tournamentService.startKnockout(token, clubId, tournamentId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: "K.o.-Runde erfolgreich gestartet" });
    } catch (error) {
        const status = /Gruppenmodus|Zu wenige Qualifikanten/.test(error.message) ? 400 : 500;
        res.status(status).json({ error: error.message });
    }
};

export const manualAssignGroups = async (req, res) => {
    const { authcode: token } = req.headers;
    const {
        clubId,
        tournamentId,
        assignments,     // [{ participantId, groupNumber }]
        numberOfGroups,  // optional
        maxGroupSize     // optional
    } = req.body;

    try {
        const groupsWithParts = await tournamentService.manualAssignGroups(
            token,
            clubId,
            tournamentId,
            assignments,
            numberOfGroups,  // neu
            maxGroupSize     // neu
        );
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(groupsWithParts);
    } catch (error) {
        console.error('Error in manualAssignGroups:', error);
        res.status(500).json({ error: error.message });
    }
};

export const assignParticipantToGroup = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, participantId, groupNumber, isExternal } = req.body;
    
    try {
        const groups = await tournamentService.assignParticipantToGroup(
            token,
            clubId,
            tournamentId,
            participantId,
            groupNumber,
            isExternal || false
        );
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(groups);
    } catch (error) {
        console.error('Error in assignParticipantToGroup:', error);
        res.status(500).json({ error: error.message });
    }
};

export const resetGroups = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.body;
    try {
        await tournamentService.resetGroups(token, clubId, tournamentId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.sendStatus(204);
    } catch (err) {
        console.error(err);
        res.status(500).json({ error: err.message });
    }
};

export const resetMatches = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.body;
    try {
        await tournamentService.resetMatches(token, clubId, tournamentId, classId || null);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.sendStatus(204);
    } catch (err) {
        console.error(err);
        res.status(500).json({ error: err.message });
    }
};

export const removeParticipant = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, participantId } = req.body;
    try {
        await tournamentService.removeParticipant(token, clubId, tournamentId, participantId);
        const participants = await tournamentService.getParticipants(token, clubId, tournamentId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(participants);
    } catch (err) {
        console.error(err);
        res.status(500).json({ error: err.message });
    }
};

export const updateParticipantSeeded = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, participantId } = req.params;
    const { seeded } = req.body;
    try {
        await tournamentService.updateParticipantSeeded(token, clubId, tournamentId, participantId, seeded);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Gesetzt-Status aktualisiert' });
    } catch (err) {
        console.error('[updateParticipantSeeded] Error:', err);
        res.status(500).json({ error: err.message });
    }
};

export const deleteMatchResult = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, matchId, set } = req.body;
    try {
        await tournamentService.deleteMatchResult(
            token,
            clubId,
            tournamentId,
            matchId,
            set
        );
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Einzelsatz gelöscht' });
    } catch (error) {
        console.error('Error in deleteMatchResult:', error);
        res.status(500).json({ error: error.message });
    }
};


export const reopenMatch = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, matchId } = req.body;
    try {
        await tournamentService.reopenMatch(token, clubId, tournamentId, matchId);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        // Gib optional das aktualisierte Match zurück
        res.status(200).json({ message: "Match reopened" });
    } catch (error) {
        console.error("Error in reopenMatch:", error);
        res.status(500).json({ error: error.message });
    }
};

export const deleteKnockoutMatches = async (req, res) => {
    const { authcode: token } = req.headers;
        const { clubId, tournamentId, classId } = req.body;
    try {
            await tournamentService.resetKnockout(token, clubId, tournamentId, classId);
      // Emit Socket-Event
      emitTournamentChanged(clubId, tournamentId);
      res.status(200).json({ message: "K.o.-Runde gelöscht" });
    } catch (error) {
      console.error("Error in deleteKnockoutMatches:", error);
      res.status(500).json({ error: error.message });
    }
  };

export const setMatchActive = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, matchId } = req.params;
    const { isActive } = req.body;
    try {
        await tournamentService.setMatchActive(token, clubId, tournamentId, matchId, isActive);
        // Emit Socket-Event
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Match-Status aktualisiert' });
    } catch (err) {
        console.error('[setMatchActive] Error:', err);
        res.status(500).json({ error: err.message });
    }
};

// Externe Teilnehmer hinzufügen
export const addExternalParticipant = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId, firstName, lastName, club, birthDate, gender } = req.body;
    try {
        await tournamentService.addExternalParticipant(token, clubId, classId, firstName, lastName, club, birthDate, gender);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Externer Teilnehmer hinzugefügt' });
    } catch (error) {
        console.error('[addExternalParticipant] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// Externe Teilnehmer abrufen - nach Klasse oder Turnier
export const getExternalParticipants = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.body;
    try {
        const participants = await tournamentService.getExternalParticipants(token, clubId, tournamentId, classId || null);
        res.status(200).json(participants);
    } catch (error) {
        console.error('[getExternalParticipants] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// Externe Teilnehmer löschen
export const removeExternalParticipant = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, participantId } = req.body;
    try {
        await tournamentService.removeExternalParticipant(token, clubId, tournamentId, participantId);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Externer Teilnehmer entfernt' });
    } catch (error) {
        console.error('[removeExternalParticipant] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// Gesetzt-Status für externe Teilnehmer aktualisieren
export const updateExternalParticipantSeeded = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, participantId } = req.params;
    const { seeded } = req.body;
    try {
        await tournamentService.updateExternalParticipantSeeded(token, clubId, tournamentId, participantId, seeded);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Gesetzt-Status aktualisiert' });
    } catch (error) {
        console.error('[updateExternalParticipantSeeded] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// Tournament Classes
export const getTournamentClasses = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.params;
    try {
        const classes = await tournamentService.getTournamentClasses(token, clubId, tournamentId);
        res.status(200).json(classes);
    } catch (error) {
        console.error('[getTournamentClasses] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const addTournamentClass = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId } = req.params;
    const { name, isDoubles, gender, minBirthYear } = req.body;
    try {
        const tournamentClass = await tournamentService.addTournamentClass(token, clubId, tournamentId, name, isDoubles, gender, minBirthYear);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(tournamentClass);
    } catch (error) {
        console.error('[addTournamentClass] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const updateTournamentClass = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.params;
    const { name, sortOrder, isDoubles, gender, minBirthYear } = req.body;
    try {
        console.log('[updateTournamentClass] Request body:', { name, sortOrder, isDoubles, gender, minBirthYear });
        const tournamentClass = await tournamentService.updateTournamentClass(token, clubId, tournamentId, classId, name, sortOrder, isDoubles, gender, minBirthYear);
        console.log('[updateTournamentClass] Updated class:', JSON.stringify(tournamentClass.toJSON(), null, 2));
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(tournamentClass);
    } catch (error) {
        console.error('[updateTournamentClass] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const deleteTournamentClass = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.params;
    try {
        await tournamentService.deleteTournamentClass(token, clubId, tournamentId, classId);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Klasse gelöscht' });
    } catch (error) {
        console.error('[deleteTournamentClass] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const updateParticipantClass = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, participantId } = req.params;
    const { classId, isExternal } = req.body;
    try {
        await tournamentService.updateParticipantClass(token, clubId, tournamentId, participantId, classId, isExternal);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Klasse aktualisiert' });
    } catch (error) {
        console.error('[updateParticipantClass] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

// Tournament Pairings
export const getPairings = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.params;
    try {
        const pairings = await tournamentService.getPairings(token, clubId, tournamentId, classId);
        res.status(200).json(pairings);
    } catch (error) {
        console.error('[getPairings] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const createPairing = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, classId } = req.params;
    const { player1Type, player1Id, player2Type, player2Id, seeded, groupId } = req.body;
    try {
        const pairing = await tournamentService.createPairing(token, clubId, tournamentId, classId, player1Type, player1Id, player2Type, player2Id, seeded, groupId);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(pairing);
    } catch (error) {
        console.error('[createPairing] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const updatePairing = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, pairingId } = req.params;
    const { player1Type, player1Id, player2Type, player2Id, seeded, groupId } = req.body;
    try {
        const pairing = await tournamentService.updatePairing(token, clubId, tournamentId, pairingId, player1Type, player1Id, player2Type, player2Id, seeded, groupId);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json(pairing);
    } catch (error) {
        console.error('[updatePairing] Error:', error);
        res.status(500).json({ error: error.message });
    }
};

export const deletePairing = async (req, res) => {
    const { authcode: token } = req.headers;
    const { clubId, tournamentId, pairingId } = req.params;
    try {
        await tournamentService.deletePairing(token, clubId, tournamentId, pairingId);
        emitTournamentChanged(clubId, tournamentId);
        res.status(200).json({ message: 'Paarung gelöscht' });
    } catch (error) {
        console.error('[deletePairing] Error:', error);
        res.status(500).json({ error: error.message });
    }
};
  