import logging
from asyncio import sleep
from functools import partial
from typing import Optional, Union, Literal

from from_root import from_root
from rio import Column, Component, event, TextStyle, Text, Row, Image, Spacer, ProgressCircle, Button, Checkbox, ThemeContextSwitcher, Link, Revealer, PointerEventListener, \
    PointerEvent, Rectangle, Color, Popup, Dropdown

from src.ezgg_lan_manager import ConfigurationService, TournamentService, UserService, TicketingService, TeamService, RefreshService
from src.ezgg_lan_manager.components.MainViewContentBox import MainViewContentBox
from src.ezgg_lan_manager.components.TournamentDetailsInfoRow import TournamentDetailsInfoRow
from src.ezgg_lan_manager.types.DateUtil import weekday_to_display_text
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 TournamentStatus, tournament_status_to_display_text, tournament_format_to_display_texts, 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 TournamentDetailsPage(Component):
    tournament: Optional[Union[Tournament, str]] = None
    rules_accepted: bool = False
    user: Optional[User] = None
    user_teams: list[Team] = []
    loading: bool = False
    participant_revealer_open: bool = False
    current_tournament_user_or_team_list: Union[list[User], list[Team]] = []
    team_dialog_open: bool = False
    team_register_options: dict[str, Optional[Team]] = {"": None}
    team_selected_for_register: Optional[Team] = None

    # State for message above register button
    message: str = ""
    is_success: 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}")
                if self.tournament.participant_type == ParticipantType.PLAYER:
                    self.current_tournament_user_or_team_list = await self.session[TournamentService].get_users_from_participant_list(self.tournament.participants)
                elif self.tournament.participant_type == ParticipantType.TEAM:
                    self.current_tournament_user_or_team_list = await self.session[TournamentService].get_teams_from_participant_list(self.tournament.participants)
        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)
            self.user_teams = await self.session[TeamService].get_teams_for_user_by_id(user_id)
        except KeyError:
            self.user = None
            self.user_teams = []

        self.session[RefreshService].subscribe(self.on_populate)

        self.loading_done()

    @staticmethod
    async def artificial_delay() -> None:
        await sleep(0.8)  # https://medium.com/design-bootcamp/ux-psychology-of-artificial-waiting-enhancing-user-experiences-through-deliberate-delays-d7822faf3930

    async def update(self) -> None:
        if isinstance(self.tournament, Tournament):
            self.tournament = await self.session[TournamentService].get_tournament_by_id(self.tournament.id)
            if self.tournament is None or isinstance(self.tournament, str):
                return
            if self.tournament.participant_type == ParticipantType.PLAYER:
                self.current_tournament_user_or_team_list = await self.session[TournamentService].get_users_from_participant_list(self.tournament.participants)
            elif self.tournament.participant_type == ParticipantType.TEAM:
                self.current_tournament_user_or_team_list = await self.session[TournamentService].get_teams_from_participant_list(self.tournament.participants)

    def open_close_participant_revealer(self, _: PointerEvent) -> None:
        self.participant_revealer_open = not self.participant_revealer_open

    async def register_pressed(self) -> None:
        self.loading = True
        if not self.user:
            return

        user_ticket = await self.session[TicketingService].get_user_ticket(self.user.user_id)
        if user_ticket is None:
            self.is_success = False
            self.message = "Turnieranmeldung nur mit Ticket"
        elif not isinstance(self.tournament, Tournament):
            self.is_success = False
            self.message = "Fehler bei der Anmeldung"
        else:
            # Register single player
            if self.tournament.participant_type == ParticipantType.PLAYER:
                try:
                    await self.session[TournamentService].register_user_for_tournament(self.user.user_id, self.tournament.id)
                    await self.artificial_delay()
                    self.is_success = True
                    self.message = f"Erfolgreich angemeldet!"
                except Exception as e:
                    logger.error(e)
                    self.is_success = False
                    self.message = f"Fehler: {e}"
            # Register team
            elif self.tournament.participant_type == ParticipantType.TEAM:
                try:
                    team_register_options = {"": None}
                    for team in self.user_teams:
                        if team.members[self.user] == TeamStatus.OFFICER or team.members[self.user] == TeamStatus.LEADER:
                            team_register_options[team.name] = team
                    if team_register_options:
                        self.team_register_options = team_register_options
                    else:
                        self.team_register_options = {"": None}
                except StopIteration as e:
                    logger.error(f"Error trying to teams to register: {e}")
                self.team_dialog_open = True
                return  # Model should handle loading state now
            else:
                pass
        await self.update()
        self.loading = False

    async def on_team_register_confirmed(self) -> None:
        if self.team_selected_for_register is None:
            await self.on_team_register_canceled()
            return
        try:
            if isinstance(self.tournament, Tournament):
                await self.session[TournamentService].register_team_for_tournament(self.team_selected_for_register.id, self.tournament.id)
                await self.artificial_delay()
                self.is_success = True
                self.message = f"Erfolgreich angemeldet!"
                self.team_dialog_open = False
                self.team_selected_for_register = None
            else:
                raise ValueError("Turnier nicht gefunden")
        except Exception as e:
            logger.error(e)
            self.message = f"Fehler: {e}"
            self.is_success = False
        await self.update()
        self.loading = False

    async def on_team_register_canceled(self) -> None:
        self.team_dialog_open = False
        self.team_selected_for_register = None
        self.loading = False

    async def unregister_pressed(self, team: Optional[Team] = None) -> None:
        self.loading = True
        if not self.user:
            return

        try:
            if isinstance(self.tournament, Tournament) and self.tournament.participant_type == ParticipantType.PLAYER:
                await self.session[TournamentService].unregister_user_from_tournament(self.user.user_id, self.tournament.id)
            elif isinstance(self.tournament, Tournament) and self.tournament.participant_type == ParticipantType.TEAM:
                if team.members[self.user] == TeamStatus.OFFICER or team.members[self.user] == TeamStatus.LEADER:
                    await self.session[TournamentService].unregister_team_from_tournament(team.id, self.tournament.id)
                else:
                    raise PermissionError("Nur Leiter und Offiziere können das Team abmelden")
            await self.artificial_delay()
            self.is_success = True
            self.message = f"Erfolgreich abgemeldet!"
        except Exception as e:
            self.is_success = False
            self.message = f"Fehler: {e}"
        await self.update()
        self.loading = False

    async def tree_button_clicked(self) -> None:
        if isinstance(self.tournament, Tournament):
            self.session.navigate_to(f"tournament-tree?id={self.tournament.id}")

    def loading_done(self) -> None:
        if self.tournament is None:
            self.tournament = "Turnier konnte nicht gefunden werden"

    def build(self) -> Component:
        if self.tournament is None:
            content = Column(
                ProgressCircle(
                    color="secondary",
                    align_x=0.5,
                    margin_top=0,
                    margin_bottom=0
                ),
                min_height=10
            )
        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:
            tournament_status_color = self.session.theme.background_color
            tree_button = Spacer(grow_x=False, grow_y=False)
            if self.tournament.status == TournamentStatus.OPEN:
                tournament_status_color = self.session.theme.success_color
            elif self.tournament.status == TournamentStatus.CLOSED:
                tournament_status_color = self.session.theme.danger_color
            elif self.tournament.status == TournamentStatus.ONGOING or self.tournament.status == TournamentStatus.COMPLETED:
                tournament_status_color = self.session.theme.warning_color
                if self.tournament.format != TournamentFormat.FFA:
                    tree_button = Button(
                        content="Turnierbaum anzeigen",
                        shape="rectangle",
                        style="minor",
                        color="hud",
                        margin_left=4,
                        margin_right=4,
                        margin_top=1,
                        on_press=self.tree_button_clicked
                    )

            ids_of_participants = [p.id for p in self.tournament.participants]
            color_key: Literal["hud", "danger"] = "hud"
            on_press_function = self.register_pressed
            if self.tournament.participant_type == ParticipantType.PLAYER:
                self.current_tournament_user_or_team_list: list[User]  # IDE TypeHint
                participant_names = "\n".join([u.user_name for u in self.current_tournament_user_or_team_list])
                if self.user and self.user.user_id in ids_of_participants:  # User already registered for tournament
                    button_text = "Abmelden"
                    button_sensitive_hook = True  # User has already accepted the rules previously
                    color_key = "danger"
                    on_press_function = self.unregister_pressed
                elif self.user and self.user.user_id not in ids_of_participants:
                    button_text = "Anmelden"
                    button_sensitive_hook = self.rules_accepted
                else:
                    # This should NEVER happen
                    button_text = "Anmelden"
                    button_sensitive_hook = False
            elif self.tournament.participant_type == ParticipantType.TEAM:
                self.current_tournament_user_or_team_list: list[Team]  # IDE TypeHint
                participant_names = "\n".join([t.name for t in self.current_tournament_user_or_team_list])
                user_team_registered = []
                for team in self.user_teams:
                    if team.id in ids_of_participants:
                        user_team_registered.append(team)
                if self.user and len(user_team_registered) > 0:  # Any of the users teams already registered for tournament
                    button_text = f"{user_team_registered[0].abbreviation} abmelden"
                    button_sensitive_hook = True  # User has already accepted the rules previously
                    color_key = "danger"
                    on_press_function = partial(self.unregister_pressed, user_team_registered[0])
                elif self.user and len(user_team_registered) == 0:
                    button_text = "Anmelden"
                    button_sensitive_hook = self.rules_accepted
                else:
                    # This should NEVER happen
                    button_text = "Anmelden"
                    button_sensitive_hook = False
            else:
                logger.fatal("Did someone add new values to ParticipantType ? ;)")
                return Column()


            if self.tournament.status != TournamentStatus.OPEN or self.tournament.is_full:
                button_sensitive_hook = False  # Override button controls if tournament is not open anymore or full

            if self.user:
                accept_rules_row = Row(
                    ThemeContextSwitcher(content=Checkbox(is_on=self.bind().rules_accepted, margin_left=4), color=self.session.theme.hud_color),
                    Text("Ich akzeptiere die ", margin_left=1, style=TextStyle(fill=self.session.theme.background_color, font_size=0.8), overflow="nowrap", justify="right"),
                    Link(Text("Turnierregeln", margin_right=4, style=TextStyle(fill=self.session.theme.background_color, font_size=0.8, italic=True), overflow="nowrap", justify="left"), "./tournament-rules", open_in_new_tab=True)
                )
                button = Button(
                    content=button_text,
                    shape="rectangle",
                    style="major",
                    color=color_key,
                    margin_left=2,
                    margin_right=2,
                    is_sensitive=button_sensitive_hook,
                    on_press=on_press_function,
                    is_loading=self.loading
                )
            else:
                # No UI here if user not logged in
                accept_rules_row, button = Spacer(), Spacer()

            content = Column(
                Row(
                    Image(image=from_root(f"src/ezgg_lan_manager/assets/img/games/{self.tournament.game_title.image_name}"), margin_right=1),
                    Text(
                        text=self.tournament.name,
                        style=TextStyle(
                            fill=self.session.theme.background_color,
                            font_size=1.2
                        ),
                        margin_top=1,
                        margin_bottom=1,
                        align_x=0.5
                    ),
                    margin_right=6,
                    margin_left=6
                ),
                Spacer(min_height=1),
                TournamentDetailsInfoRow("Status", tournament_status_to_display_text(self.tournament.status), value_color=tournament_status_color),
                TournamentDetailsInfoRow("Startzeit", f"{weekday_to_display_text(self.tournament.start_time.weekday())}, {self.tournament.start_time.strftime('%H:%M')} Uhr"),
                TournamentDetailsInfoRow("Format", tournament_format_to_display_texts(self.tournament.format)[0]),
                TournamentDetailsInfoRow("Best of", tournament_format_to_display_texts(self.tournament.format)[1]),
                PointerEventListener(
                    content=Rectangle(
                        content=TournamentDetailsInfoRow(
                            "Teilnehmer ▴" if self.participant_revealer_open else "Teilnehmer ▾",
                            f"{len(self.current_tournament_user_or_team_list)} / {self.tournament.max_participants}",
                            value_color=self.session.theme.danger_color if self.tournament.is_full else self.session.theme.background_color,
                            key_color=self.session.theme.secondary_color
                        ),
                        fill=Color.TRANSPARENT,
                        cursor="pointer"
                    ),
                    on_press=self.open_close_participant_revealer
                ),
                Revealer(
                    header=None,
                    content=Text(
                        participant_names,
                        style=TextStyle(fill=self.session.theme.background_color)
                    ),
                    is_open=self.participant_revealer_open,
                    margin_left=4,
                    margin_right=4
                ),
                tree_button,
                Row(
                    Text(
                        text="Info",
                        style=TextStyle(
                            fill=self.session.theme.background_color,
                            font_size=1.2
                        ),
                        margin_top=1,
                        margin_bottom=1,
                        align_x=0.5
                    )
                ),
                # FixMe: Use rio.Markdown with correct TextStyle instead to allow basic text formatting from DB-side.
                Text(self.tournament.description, margin_left=2, margin_right=2, style=TextStyle(fill=self.session.theme.background_color, font_size=1), overflow="wrap"),
                Spacer(min_height=2),
                accept_rules_row,
                Spacer(min_height=0.5),
                Text(self.message, margin_left=2, margin_right=2, style=TextStyle(fill=self.session.theme.success_color if self.is_success else self.session.theme.danger_color, font_size=1), overflow="wrap", justify="center"),
                Spacer(min_height=0.5),
                button
            )

        if isinstance(self.tournament, Tournament) and self.tournament.participant_type == ParticipantType.TEAM:
            content = Popup(
                anchor=content,
                content=Rectangle(
                    content=Column(
                        Text("Welches Team anmelden?", style=TextStyle(fill=self.session.theme.background_color, font_size=1.2), justify="center", margin_bottom=1),
                        ThemeContextSwitcher(
                            content=Dropdown(
                                options=self.team_register_options,
                                min_width=20,
                                selected_value=self.bind().team_selected_for_register
                            ),
                            color=self.session.theme.hud_color,
                            margin_bottom=1
                        ),
                        Row(
                            Button(content="Abbrechen", shape="rectangle", grow_x=False, on_press=self.on_team_register_canceled),
                            Button(content="Anmelden", shape="rectangle", grow_x=False, on_press=self.on_team_register_confirmed),
                            spacing=1
                        ),
                        margin=0.5
                    ),
                    min_width=30,
                    min_height=4,
                    fill=self.session.theme.primary_color,
                    margin_top=3.5,
                    stroke_width=0.3,
                    stroke_color=self.session.theme.neutral_color,
                ),
                is_open=self.team_dialog_open,
                color="none"
            )

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