import math
import uuid
from datetime import datetime, timezone
from typing import List, Dict, Any, Optional

def now_iso() -> str:
    return datetime.now(timezone.utc).isoformat()

def get_round_name(round_num: int, total_rounds: int) -> str:
    diff = total_rounds - round_num
    if diff == 0:
        return "Marea Finală"
    elif diff == 1:
        return "Semifinale"
    elif diff == 2:
        return "Sferturi de Finală"
    elif diff == 3:
        return "Optimi de Finală"
    elif diff == 4:
        return "Șaisprezecimi"
    return f"Runda {round_num}"

def generate_single_elimination_bracket(tournament_id: str, teams: List[Dict[str, Any]], format_type: str = "BO1") -> List[Dict[str, Any]]:
    """
    Generates a full single elimination bracket tree with linked nodes for automatic advancement.
    """
    n = len(teams)
    if n < 2:
        raise ValueError("Minim 2 echipe sunt necesare pentru a genera bracket-ul")

    # Next power of 2
    bracket_size = 2 ** math.ceil(math.log2(n))
    total_rounds = int(math.log2(bracket_size))

    # Pad with BYEs
    padded_teams = list(teams)
    while len(padded_teams) < bracket_size:
        padded_teams.append({
            "id": f"bye_{len(padded_teams)}",
            "name": "BYE (Liber)",
            "tag": "BYE",
            "logo": "",
            "is_bye": True
        })

    # Generate all match placeholders from Final backwards or round by round
    # round_matches[round_num] = list of match dicts
    rounds_data: Dict[int, List[Dict[str, Any]]] = {}
    
    # 1. Create skeleton for all rounds
    for r in range(1, total_rounds + 1):
        matches_in_round = bracket_size // (2 ** r)
        rounds_data[r] = []
        r_name = get_round_name(r, total_rounds)
        for pos in range(matches_in_round):
            m_id = f"tm_{tournament_id[:8]}_r{r}_m{pos}_{uuid.uuid4().hex[:6]}"
            rounds_data[r].append({
                "id": m_id,
                "tournament_id": tournament_id,
                "round": r,
                "round_name": r_name,
                "position": pos,
                "format": "BO3" if r == total_rounds and format_type == "BO3" else format_type,
                "team1": None,
                "team2": None,
                "team1_score": 0,
                "team2_score": 0,
                "winner_id": None,
                "winner_team": None,
                "status": "upcoming",
                "map_name": "de_dust2",
                "next_match_id": None,
                "next_match_slot": None,  # "team1" or "team2"
                "server_ip": None,
                "server_port": None,
                "server_password": None,
                "checkin_deadline": None,
                "created_at": now_iso()
            })

    # 2. Link each match to its parent in next round
    for r in range(1, total_rounds):
        for pos, m in enumerate(rounds_data[r]):
            next_pos = pos // 2
            next_slot = "team1" if pos % 2 == 0 else "team2"
            m["next_match_id"] = rounds_data[r + 1][next_pos]["id"]
            m["next_match_slot"] = next_slot

    # 3. Populate Round 1 teams
    r1_matches = rounds_data[1]
    for i in range(len(r1_matches)):
        t1 = padded_teams[i * 2]
        t2 = padded_teams[i * 2 + 1]
        
        r1_matches[i]["team1"] = t1
        r1_matches[i]["team2"] = t2

        # Auto-handle BYEs in Round 1
        if t2.get("is_bye") and not t1.get("is_bye"):
            r1_matches[i]["winner_id"] = t1["id"]
            r1_matches[i]["winner_team"] = t1
            r1_matches[i]["team1_score"] = 1
            r1_matches[i]["team2_score"] = 0
            r1_matches[i]["status"] = "finished"
        elif t1.get("is_bye") and not t2.get("is_bye"):
            r1_matches[i]["winner_id"] = t2["id"]
            r1_matches[i]["winner_team"] = t2
            r1_matches[i]["team1_score"] = 0
            r1_matches[i]["team2_score"] = 1
            r1_matches[i]["status"] = "finished"
        elif not t1.get("is_bye") and not t2.get("is_bye"):
            r1_matches[i]["status"] = "ready"

    # Flatten all matches
    all_matches = []
    for r in range(1, total_rounds + 1):
        all_matches.extend(rounds_data[r])

    # 4. Propagate any Round 1 BYE winners into Round 2 immediately
    matches_dict = {m["id"]: m for m in all_matches}
    for m in r1_matches:
        if m["status"] == "finished" and m["winner_team"] and m["next_match_id"]:
            next_m = matches_dict.get(m["next_match_id"])
            if next_m:
                next_m[m["next_match_slot"]] = m["winner_team"]
                if next_m.get("team1") and next_m.get("team2"):
                    if not next_m["team1"].get("is_bye") and not next_m["team2"].get("is_bye"):
                        next_m["status"] = "ready"

    return all_matches


async def advance_bracket_winner(db, match_id: str, winning_team_slot: str, score1: int, score2: int, server_pool = None) -> Dict[str, Any]:
    """
    Advances the winner of a match to the next bracket node in real time.
    """
    match = await db.idg_matches.find_one({"id": match_id})
    if not match:
        raise ValueError(f"Match {match_id} not found")

    team1 = match.get("team1")
    team2 = match.get("team2")
    
    if winning_team_slot == "team1":
        winner = team1
    elif winning_team_slot == "team2":
        winner = team2
    else:
        # Determine by score
        winner = team1 if score1 > score2 else team2

    if not winner:
        raise ValueError("Cannot determine winning team")

    # 1. Mark current match finished
    await db.idg_matches.update_one(
        {"id": match_id},
        {"$set": {
            "status": "finished",
            "team1_score": score1,
            "team2_score": score2,
            "winner_id": winner.get("id"),
            "winner_team": winner,
            "finished_at": now_iso()
        }}
    )

    # Free up server if assigned
    if server_pool and match.get("server_ip"):
        await server_pool.release_server(match_id)

    tournament_id = match.get("tournament_id")
    next_match_id = match.get("next_match_id")
    next_slot = match.get("next_match_slot")

    # 2. Advance to next round if exists
    if next_match_id and next_slot:
        next_match = await db.idg_matches.find_one({"id": next_match_id})
        if next_match:
            update_fields = {next_slot: winner}
            
            # Check if opposing team is already present
            opposing_slot = "team2" if next_slot == "team1" else "team1"
            opponent = next_match.get(opposing_slot)
            
            if opponent and not opponent.get("is_bye"):
                update_fields["status"] = "ready"
                
                # Auto-assign server from pool for upcoming match
                if server_pool:
                    server_info = await server_pool.assign_server(
                        tournament_id=tournament_id,
                        match_id=next_match_id,
                        game=match.get("game", "cs16")
                    )
                    if server_info:
                        update_fields.update(server_info)

            await db.idg_matches.update_one(
                {"id": next_match_id},
                {"$set": update_fields}
            )
            return {"advanced": True, "next_match_id": next_match_id, "winner": winner}
    else:
        # GRAND FINAL FINISHED! Declare Tournament Champion
        tournament = await db.idg_tournaments.find_one({"id": tournament_id})
        if tournament:
            await db.idg_tournaments.update_one(
                {"id": tournament_id},
                {"$set": {
                    "status": "finished",
                    "champion": winner,
                    "finished_at": now_iso()
                }}
            )
            
            # Award wallet credits / prize if defined
            prize_pool_str = str(tournament.get("prize_pool", "0"))
            try:
                import re
                nums = re.findall(r"\d+", prize_pool_str)
                prize_amount = int(nums[0]) if nums else 0
                if prize_amount > 0 and winner.get("leader_id"):
                    await db.users.update_one(
                        {"id": winner["leader_id"]},
                        {"$inc": {"coins": prize_amount}}
                    )
            except Exception as e:
                print("Error awarding prize:", e)

            return {"advanced": False, "tournament_completed": True, "champion": winner}

    return {"advanced": True, "winner": winner}
