from db import get_connection from repositories.team_repository import get_team_id_by_external_id def upsert_coach( external_id: str, team_external_id: str, player: str, lastname: str = "", name: str = "", born: str = "", amplua: str = "", is_active: bool = True, ) -> None: team_id = get_team_id_by_external_id(str(team_external_id).strip()) if team_id is None: raise ValueError(f"Team not found by external_id: {team_external_id}") query = """ INSERT INTO coaches ( external_id, team_id, player, lastname, name, born, amplua, is_active, created_at, updated_at ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, NOW(), NOW()) ON CONFLICT (external_id) DO UPDATE SET team_id = EXCLUDED.team_id, player = EXCLUDED.player, lastname = EXCLUDED.lastname, name = EXCLUDED.name, born = EXCLUDED.born, amplua = EXCLUDED.amplua, is_active = EXCLUDED.is_active, updated_at = NOW(); """ conn = get_connection() try: with conn.cursor() as cur: cur.execute( query, ( str(external_id).strip(), team_id, player.strip(), lastname.strip(), name.strip(), born.strip(), amplua.strip(), is_active, ), ) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def get_player_id_by_name_and_team(full_name: str, team_id: int) -> int | None: query = """ SELECT id FROM players WHERE team_id = %s AND LOWER(full_name) = LOWER(%s) LIMIT 1; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute(query, (team_id, full_name.strip())) row = cur.fetchone() return row[0] if row else None finally: conn.close() def get_coach_id_by_name_and_team(full_name: str, team_id: int) -> int | None: query = """ SELECT id FROM coaches WHERE team_id = %s AND LOWER(player) = LOWER(%s) LIMIT 1; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute(query, (team_id, full_name.strip())) row = cur.fetchone() return row[0] if row else None finally: conn.close() def get_coach_id_by_external_id(external_id: str) -> int | None: query = """ SELECT id FROM coaches WHERE external_id = %s LIMIT 1; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute(query, (str(external_id).strip(),)) row = cur.fetchone() return row[0] if row else None finally: conn.close() def _split_coach_name_for_autocreate(full_name: str) -> tuple[str, str]: parts = [p.strip() for p in str(full_name or "").replace("\xa0", " ").split() if p.strip()] if not parts: return "", "" if len(parts) == 1: return "", parts[0] first_name = parts[0] last_name = " ".join(parts[1:]) return first_name, last_name def create_coach_from_lineup( team_id: int, external_id: str = "", full_name: str = "", role: str = "", ) -> int | None: """Создаёт минимальную карточку тренера из протокола матча.""" full_name = str(full_name or "").strip() if not full_name: return None first_name, last_name = _split_coach_name_for_autocreate(full_name) external_id = str(external_id or "").strip() role = str(role or "").strip() query = """ INSERT INTO coaches ( external_id, team_id, player, lastname, name, amplua, is_active, created_at, updated_at ) VALUES (NULLIF(%s, ''), %s, %s, %s, %s, %s, TRUE, NOW(), NOW()) ON CONFLICT (external_id) DO UPDATE SET team_id = EXCLUDED.team_id, player = COALESCE(NULLIF(EXCLUDED.player, ''), coaches.player), lastname = COALESCE(NULLIF(EXCLUDED.lastname, ''), coaches.lastname), name = COALESCE(NULLIF(EXCLUDED.name, ''), coaches.name), amplua = COALESCE(NULLIF(EXCLUDED.amplua, ''), coaches.amplua), is_active = TRUE, updated_at = NOW() RETURNING id; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute( query, ( external_id, team_id, full_name, last_name, first_name, role, ), ) row = cur.fetchone() conn.commit() return row[0] if row else None except Exception: conn.rollback() raise finally: conn.close() def search_coaches_for_admin(q: str = "") -> list[dict]: conn = get_connection() try: with conn.cursor() as cur: if q.strip(): pattern = f"%{q.strip()}%" cur.execute( """ SELECT c.id, c.player, c.external_id, c.amplua, t.name AS team_name FROM coaches c LEFT JOIN teams t ON t.id = c.team_id WHERE c.player ILIKE %s OR COALESCE(c.external_id, '') ILIKE %s OR COALESCE(c.amplua, '') ILIKE %s OR COALESCE(t.name, '') ILIKE %s ORDER BY c.player ASC, c.id ASC LIMIT 200 """, (pattern, pattern, pattern, pattern), ) else: cur.execute( """ SELECT c.id, c.player, c.external_id, c.amplua, t.name AS team_name FROM coaches c LEFT JOIN teams t ON t.id = c.team_id ORDER BY c.id DESC LIMIT 200 """ ) rows = cur.fetchall() return [ { "id": row[0], "full_name": row[1] or "", "external_id": row[2] or "", "role": row[3] or "", "team_name": row[4] or "", } for row in rows ] finally: conn.close() def get_coach_by_id(coach_id: int) -> dict | None: conn = get_connection() try: with conn.cursor() as cur: cur.execute( """ SELECT c.id, c.player, c.external_id, c.amplua, c.team_id, t.name AS team_name FROM coaches c LEFT JOIN teams t ON t.id = c.team_id WHERE c.id = %s LIMIT 1 """, (coach_id,), ) row = cur.fetchone() if not row: return None return { "id": row[0], "full_name": row[1] or "", "external_id": row[2] or "", "role": row[3] or "", "team_id": row[4], "team_name": row[5] or "", } finally: conn.close() def get_coach_by_id(coach_id: int) -> dict | None: conn = get_connection() try: with conn.cursor() as cur: cur.execute( """ SELECT c.id, c.player, c.external_id, c.amplua, c.team_id, t.name AS team_name FROM coaches c LEFT JOIN teams t ON t.id = c.team_id WHERE c.id = %s LIMIT 1 """, (coach_id,), ) row = cur.fetchone() if not row: return None return { "id": row[0], "full_name": row[1] or "", "external_id": row[2] or "", "role": row[3] or "", "team_id": row[4], "team_name": row[5] or "", } finally: conn.close() def update_coach_admin( coach_id: int, full_name: str = "", external_id: str = "", role: str = "", ) -> None: conn = get_connection() try: with conn.cursor() as cur: cur.execute( """ UPDATE coaches SET player = %s, external_id = NULLIF(%s, ''), amplua = %s WHERE id = %s """, ( full_name.strip(), external_id.strip(), role.strip(), coach_id, ), ) conn.commit() except Exception: conn.rollback() raise finally: conn.close() def create_coach_admin( team_id: int, full_name: str, first_name: str = "", last_name: str = "", external_id: str = "", birth_date: str = "", role: str = "", is_active: bool = True, ) -> int: """Создаёт тренера вручную из административного раздела.""" query = """ INSERT INTO coaches ( external_id, team_id, player, lastname, name, born, amplua, is_active, created_at, updated_at ) VALUES ( NULLIF(%s, ''), %s, %s, %s, %s, NULLIF(%s, ''), %s, %s, NOW(), NOW() ) RETURNING id; """ conn = get_connection() try: with conn.cursor() as cur: cur.execute( query, ( external_id.strip(), int(team_id), full_name.strip(), last_name.strip(), first_name.strip(), birth_date.strip(), role.strip(), bool(is_active), ), ) row = cur.fetchone() conn.commit() return int(row[0]) except Exception: conn.rollback() raise finally: conn.close()