import json
import logging
from typing import Optional, Union

from from_root import from_root
from rio import Column, Component, event, TextStyle, Text, Row, Spacer, ProgressCircle, Rectangle, Stack

from src.ezgg_lan_manager import ConfigurationService, TournamentService, UserService, TeamService, RefreshService, SeatingService
from src.ezgg_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ezgg_lan_manager.types.Team import Team, TeamStatus
from src.ezgg_lan_manager.types.Tournament import Tournament
from src.ezgg_lan_manager.types.TournamentBase import ParticipantType, TournamentFormat
from src.ezgg_lan_manager.types.User import User
from src.ezgg_lan_manager.types.UserSession import UserSession

logger = logging.getLogger(__name__.split(".")[-1])

class MatchInfo(Component):
    opponent_1: str = ""
    opponent_2: str = ""
    opponent_1_seat: str = ""
    opponent_2_seat: str = ""
    winner: str = ""

    def build(self) -> Component:
        return Rectangle(
            content=Column(
                Stack(
                    Row(
                        Row(
                            Text(
                                text=self.opponent_1,
                                style=TextStyle(fill=self.session.theme.success_color if self.winner == self.opponent_1 else self.session.theme.background_color),
                                justify="left",
                                margin_right=0.6,
                                font_size=0.9
                            ),
                            Text(
                                text=f"({self.opponent_1_seat})" if self.opponent_1_seat else "Freilos",
                                style=TextStyle(fill=self.session.theme.background_color),
                                justify="left",
                                font_size=0.9
                            )
                        ),
                        Spacer(),
                        Row(
                            Text(
                                text=self.opponent_2,
                                style=TextStyle(fill=self.session.theme.success_color if self.winner == self.opponent_2 else self.session.theme.background_color),
                                justify="right",
                                margin_right=0.6,
                                font_size=0.9
                            ),
                            Text(
                                text=f"({self.opponent_2_seat})" if self.opponent_2_seat else "Freilos",
                                style=TextStyle(fill=self.session.theme.background_color),
                                justify="right",
                                font_size=0.9
                            )
                        ),
                        margin=0.3
                    ),
                    Row(
                        Text(
                            text=f"vs.",
                            style=TextStyle(fill=self.session.theme.background_color),
                            justify="center"
                        ),
                        margin=0.3
                    )
                )
            ),
            margin=1,
            stroke_width=0.2,
            stroke_color=self.session.theme.background_color,
            fill=self.session.theme.hud_color,
        )

class TournamentTreePage(Component):
    tournament: Optional[Union[Tournament, str]] = None
    user: Optional[User] = None
    teams: list[Team] = []
    id_to_username_map: dict[int, str] = {}
    id_to_seat_map: dict[int, str] = {}
    is_fully_loaded: bool = False

    @event.on_populate
    async def on_populate(self) -> None:
        try:
            tournament_id = int(self.session.active_page_url.query_string.split("id=")[-1])
        except (ValueError, AttributeError, TypeError):
            tournament_id = None
        if tournament_id is not None:
            self.tournament = await self.session[TournamentService].get_tournament_by_id(tournament_id)
            if isinstance(self.tournament, Tournament):
                await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - {self.tournament.name}")
        else:
            await self.session.set_title(f"{self.session[ConfigurationService].get_lan_info().name} - Turniere")

        try:
            user_id = self.session[UserSession].user_id
            self.user = await self.session[UserService].get_user(user_id)
        except KeyError:
            self.user = None

        self.teams = await self.session[TeamService].get_all_teams()

        all_users = await self.session[UserService].get_all_users()
        id_to_username_map = {}
        id_to_seat_map = {}
        for user in all_users:
            id_to_username_map[user.user_id] = user.user_name
            seat = await self.session[SeatingService].get_user_seat(user.user_id)
            if seat is not None:
                id_to_seat_map[user.user_id] = seat.seat_id

        self.id_to_username_map = id_to_username_map
        self.id_to_seat_map = id_to_seat_map
        self.session[RefreshService].subscribe(self.on_populate)
        self.is_fully_loaded = True

    def _get_seat_for_team(self, team: Team) -> str:
        # Retrieves seat id for leader of a team
        leader = list(team.members.keys())[0]
        for member, rank in team.members.items():
            if rank == TeamStatus.LEADER:
                leader = member
                break

        return self.id_to_seat_map[leader.user_id]


    def build(self) -> Component:
        if self.tournament is None or not self.is_fully_loaded:
            return Column(
                MainViewContentBox(
                    Column(
                        Spacer(min_height=1),
                        Column(
                            ProgressCircle(
                                color="secondary",
                                align_x=0.5,
                                margin_top=0,
                                margin_bottom=0
                            ),
                            min_height=10
                        ),
                        Spacer(min_height=1)
                    )
                ),
                align_y=0
            )
        elif isinstance(self.tournament, str):
            content = Row(
                Text(
                    text=self.tournament,
                    style=TextStyle(
                        fill=self.session.theme.background_color,
                        font_size=1
                    ),
                    margin_top=2,
                    margin_bottom=2,
                    align_x=0.5
                )
            )
        else:
            if self.tournament.format == TournamentFormat.FFA:
                content = Column(
                    Text(
                        text=f"Dieses Turnier hat keinen Turnierbaum.",
                        style=TextStyle(fill=self.session.theme.background_color),
                        margin_top=1,
                        margin_bottom=1,
                        align_x=0.5,
                        overflow="wrap",
                        min_width=30,
                        justify="center"
                    )
                )
            else:
                try:
                    file_name = self.tournament.name.replace(" ", "_") + ".json"
                    games_per_matchup = int(self.tournament.format.name[-1])
                    logger.info(f"Trying to read tournament data from {file_name}")
                    with open(from_root("tournament_data", file_name), "r") as f:
                        json_data = json.load(f)

                    last_valid_round = None
                    round_num = 0
                    for round_ in json_data["rounds"]:
                        if all(
                                match["opponent_1_id"] is not None or match["opponent_2_id"] is not None
                                for match in round_
                        ):
                            last_valid_round = round_
                            round_num += 1

                    if last_valid_round is None:
                        last_valid_round = json_data["rounds"][0]

                    match_infos = []
                    if self.tournament.participant_type == ParticipantType.PLAYER:
                        match_infos = [MatchInfo(
                            opponent_1=self.id_to_username_map.get(match["opponent_1_id"], ""),
                            opponent_2=self.id_to_username_map.get(match["opponent_2_id"], ""),
                            winner=self.id_to_username_map.get(match["winner"], ""),
                            opponent_1_seat=self.id_to_seat_map.get(match["opponent_1_id"], ""),
                            opponent_2_seat=self.id_to_seat_map.get(match["opponent_2_id"], ""),
                        ) for match in last_valid_round]
                    elif self.tournament.participant_type == ParticipantType.TEAM:
                        for match in last_valid_round:
                            team_1: Optional[Team] = next(filter(lambda t: t.id == match["opponent_1_id"], self.teams), None)
                            team_2: Optional[Team] = next(filter(lambda t: t.id == match["opponent_2_id"], self.teams), None)
                            winner: Union[str, Team] = next(filter(lambda t: t.id == match["winner"], self.teams), "")
                            match_infos.append(
                                MatchInfo(
                                    opponent_1=team_1.name if team_1 is not None else "",
                                    opponent_2=team_2.name if team_2 is not None else "",
                                    winner=winner if isinstance(winner, str) else winner.name,
                                    opponent_1_seat=self._get_seat_for_team(team_1) if team_1 is not None else "",
                                    opponent_2_seat=self._get_seat_for_team(team_2) if team_2 is not None else "",
                                )
                            )
                    else:
                        raise ValueError("Unknown participant type")



                    content = Column(
                        Text(
                            text=f"{self.tournament.name}",
                            style=TextStyle(fill=self.session.theme.background_color),
                            justify="center",
                            font_size=1.2
                        ),
                        Text(
                            text="Finale" if len(json_data["rounds"]) == round_num else f"Runde {round_num}",
                            style=TextStyle(fill=self.session.theme.background_color),
                            justify="center",
                            font_size=0.9,
                            margin_bottom=1
                        ),
                        Text(
                            text=f"Spiele pro Matchup: {games_per_matchup}",
                            style=TextStyle(fill=self.session.theme.background_color),
                            justify="center",
                            font_size=0.8
                        ),
                        Text(
                            text=f"Melde als Verlierer deinen Matchausgang\nim Discord oder an der Orga-Ecke",
                            style=TextStyle(fill=self.session.theme.background_color),
                            justify="center",
                            font_size=0.8
                        ),
                        *match_infos
                    )
                except (FileNotFoundError, ValueError, AttributeError):
                    content = Column(
                        Text(
                            text=f"Der Turnierbaum für dieses Turnier steht leider nicht zur Verfügung.\n\nBitte melde sich beim Orga-Team.",
                            style=TextStyle(fill=self.session.theme.background_color),
                            margin_top=1,
                            margin_bottom=1,
                            align_x=0.5,
                            overflow="wrap",
                            min_width=30,
                            justify="center"
                        )
                    )

        return Column(
            MainViewContentBox(
                Column(
                    Spacer(min_height=1),
                    content,
                    Spacer(min_height=1)
                )
            ),
            align_y=0
        )