import { getPool } from "./database"; import { Team } from "@/lib/types"; export class TeamsService { /** * Get all teams */ static async getTeams(): Promise { const pool = getPool(); const query = ` SELECT id, name, direction FROM teams ORDER BY direction, name `; try { const result = await pool.query(query); return result.rows; } catch (error) { console.error("Error fetching teams:", error); throw new Error("Failed to fetch teams"); } } /** * Get teams by direction */ static async getTeamsByDirection(direction: string): Promise { const pool = getPool(); const query = ` SELECT id, name, direction FROM teams WHERE direction = $1 ORDER BY name `; try { const result = await pool.query(query, [direction]); return result.rows; } catch (error) { console.error("Error fetching teams by direction:", error); throw new Error("Failed to fetch teams by direction"); } } /** * Get team by ID */ static async getTeamById(id: string): Promise { const pool = getPool(); const query = ` SELECT id, name, direction FROM teams WHERE id = $1 `; try { const result = await pool.query(query, [id]); return result.rows[0] || null; } catch (error) { console.error("Error fetching team by ID:", error); throw new Error("Failed to fetch team"); } } /** * Create a new team */ static async createTeam( team: Omit ): Promise { const pool = getPool(); const query = ` INSERT INTO teams (id, name, direction) VALUES ($1, $2, $3) RETURNING id, name, direction `; try { const result = await pool.query(query, [ team.id, team.name, team.direction, ]); return result.rows[0]; } catch (error) { console.error("Error creating team:", error); throw new Error("Failed to create team"); } } /** * Update a team */ static async updateTeam( id: string, updates: Partial> ): Promise { const pool = getPool(); const fields = []; const values = []; let paramIndex = 1; if (updates.name !== undefined) { fields.push(`name = $${paramIndex++}`); values.push(updates.name); } if (updates.direction !== undefined) { fields.push(`direction = $${paramIndex++}`); values.push(updates.direction); } if (fields.length === 0) { return this.getTeamById(id); } values.push(id); const query = ` UPDATE teams SET ${fields.join(", ")} WHERE id = $${paramIndex} RETURNING id, name, direction `; try { const result = await pool.query(query, values); return result.rows[0] || null; } catch (error) { console.error("Error updating team:", error); throw new Error("Failed to update team"); } } /** * Delete a team */ static async deleteTeam(id: string): Promise { const pool = getPool(); const query = `DELETE FROM teams WHERE id = $1`; try { const result = await pool.query(query, [id]); return (result.rowCount ?? 0) > 0; } catch (error) { console.error("Error deleting team:", error); throw new Error("Failed to delete team"); } } /** * Get all directions */ static async getDirections(): Promise { const pool = getPool(); const query = ` SELECT DISTINCT direction FROM teams ORDER BY direction `; try { const result = await pool.query(query); return result.rows.map((row) => row.direction); } catch (error) { console.error("Error fetching directions:", error); throw new Error("Failed to fetch directions"); } } /** * Get all teams with member count for admin */ static async getAllTeamsWithMemberCount(): Promise< Array<{ id: string; name: string; direction: string; memberCount: number; }> > { const pool = getPool(); const query = ` SELECT t.id, t.name, t.direction, COUNT(DISTINCT u.uuid_id) as member_count FROM teams t LEFT JOIN users u ON t.id = u.team_id GROUP BY t.id, t.name, t.direction ORDER BY t.direction, t.name `; try { const result = await pool.query(query); return result.rows.map((row) => ({ id: row.id, name: row.name, direction: row.direction, memberCount: parseInt(row.member_count) || 0, })); } catch (error) { console.error("Error fetching teams with member count:", error); throw new Error("Failed to fetch teams with member count"); } } /** * Create a new team for admin */ static async createTeamForAdmin(data: { name: string; direction: string; }): Promise<{ id: string; name: string; direction: string; memberCount: number; }> { const pool = getPool(); const client = await pool.connect(); try { await client.query("BEGIN"); // Vérifier si la team existe déjà const existingTeam = await client.query( "SELECT id FROM teams WHERE LOWER(name) = LOWER($1)", [data.name] ); if (existingTeam.rows.length > 0) { throw new Error("Une équipe avec ce nom existe déjà"); } // Créer la nouvelle team const result = await client.query( `INSERT INTO teams (name, direction) VALUES ($1, $2) RETURNING id, name, direction`, [data.name, data.direction] ); await client.query("COMMIT"); const newTeam = result.rows[0]; return { id: newTeam.id, name: newTeam.name, direction: newTeam.direction, memberCount: 0, }; } catch (error) { await client.query("ROLLBACK"); throw error; } finally { client.release(); } } /** * Update a team for admin */ static async updateTeamForAdmin(data: { id: string; name: string; direction: string; }): Promise<{ id: string; name: string; direction: string; memberCount: number; }> { const pool = getPool(); const client = await pool.connect(); try { await client.query("BEGIN"); // Vérifier si la team existe const existingTeam = await client.query( "SELECT id FROM teams WHERE id = $1", [data.id] ); if (existingTeam.rows.length === 0) { throw new Error("Équipe non trouvée"); } // Vérifier si le nom existe déjà (sauf pour cette team) const duplicateName = await client.query( "SELECT id FROM teams WHERE LOWER(name) = LOWER($1) AND id != $2", [data.name, data.id] ); if (duplicateName.rows.length > 0) { throw new Error("Une équipe avec ce nom existe déjà"); } // Mettre à jour la team await client.query( `UPDATE teams SET name = $1, direction = $2 WHERE id = $3`, [data.name, data.direction, data.id] ); // Récupérer la team mise à jour const result = await client.query( `SELECT t.id, t.name, t.direction, COUNT(DISTINCT u.uuid_id) as member_count FROM teams t LEFT JOIN users u ON t.id = u.team_id WHERE t.id = $1 GROUP BY t.id, t.name, t.direction`, [data.id] ); await client.query("COMMIT"); const team = result.rows[0]; return { id: team.id, name: team.name, direction: team.direction, memberCount: parseInt(team.member_count) || 0, }; } catch (error) { await client.query("ROLLBACK"); throw error; } finally { client.release(); } } /** * Delete a team or direction for admin */ static async deleteTeamOrDirectionForAdmin(params: { id?: string; direction?: string; }): Promise<{ message: string }> { const pool = getPool(); const client = await pool.connect(); try { await client.query("BEGIN"); if (params.direction) { // Supprimer une direction entière // Vérifier d'abord si des équipes ont des membres const memberCheck = await client.query( `SELECT COUNT(*) as count FROM users u JOIN teams t ON u.team_id = t.id WHERE t.direction = $1`, [params.direction] ); const memberCount = parseInt(memberCheck.rows[0].count); if (memberCount > 0) { throw new Error( `Impossible de supprimer la direction "${params.direction}" car certaines équipes ont des membres` ); } // Supprimer toutes les équipes de la direction await client.query("DELETE FROM teams WHERE direction = $1", [ params.direction, ]); await client.query("COMMIT"); return { message: `Direction "${params.direction}" et toutes ses équipes supprimées avec succès`, }; } else if (params.id) { // Supprimer une équipe spécifique // Vérifier si la team a des membres const memberCheck = await client.query( `SELECT COUNT(*) as count FROM users WHERE team_id = $1`, [params.id] ); const memberCount = parseInt(memberCheck.rows[0].count); if (memberCount > 0) { throw new Error( "Impossible de supprimer une équipe qui contient des membres" ); } // Supprimer la team await client.query("DELETE FROM teams WHERE id = $1", [params.id]); await client.query("COMMIT"); return { message: "Équipe supprimée avec succès" }; } else { throw new Error("L'ID de l'équipe ou la direction est requis"); } } catch (error) { await client.query("ROLLBACK"); throw error; } finally { client.release(); } } /** * Get team members for admin */ static async getTeamMembersForAdmin(teamId: string): Promise< Array<{ id: string; firstName: string; lastName: string; fullName: string; joinedAt: Date; }> > { const pool = getPool(); const query = ` SELECT u.uuid_id, u.first_name, u.last_name, u.created_at FROM users u WHERE u.team_id = $1 ORDER BY u.last_name, u.first_name `; try { const result = await pool.query(query, [teamId]); return result.rows.map((row) => ({ id: row.uuid_id, firstName: row.first_name, lastName: row.last_name, fullName: `${row.first_name} ${row.last_name}`, joinedAt: row.created_at, })); } catch (error) { console.error("Error fetching team members:", error); throw new Error("Failed to fetch team members"); } } /** * Remove member from team for admin */ static async removeMemberFromTeamForAdmin(params: { teamId: string; memberId: string; }): Promise { const pool = getPool(); const client = await pool.connect(); try { await client.query("BEGIN"); // Vérifier que le membre appartient bien à cette équipe const memberCheck = await client.query( "SELECT uuid_id FROM users WHERE uuid_id = $1 AND team_id = $2", [params.memberId, params.teamId] ); if (memberCheck.rows.length === 0) { throw new Error("Membre non trouvé dans cette équipe"); } // Supprimer le membre (mettre team_id à NULL au lieu de supprimer l'utilisateur) await client.query("UPDATE users SET team_id = NULL WHERE uuid_id = $1", [ params.memberId, ]); await client.query("COMMIT"); } catch (error) { await client.query("ROLLBACK"); throw error; } finally { client.release(); } } }