# Released under the MIT License. See LICENSE for details.
#
"""Useful starting points for new classes and whatnot."""

from __future__ import annotations

import random
from typing import override

import bauiv1 as bui


def show_template_main_window() -> None:
    """Bust out a template-main-window."""

    # Pop up an auxiliary window wherever we are in the nav stack.
    bui.app.ui_v1.auxiliary_window_activate(
        win_type=TemplateMainWindow,
        win_create_call=lambda: TemplateMainWindow(
            dummy_data=random.randrange(100, 1000)
        ),
    )


class TemplateMainWindow(bui.MainWindow):
    """An example of a well-behaved main-window."""

    def __init__(
        self,
        dummy_data: int,
        *,
        transition: str | None = 'in_right',
        origin_widget: bui.Widget | None = None,
        auxiliary_style: bool = True,
    ):
        # pylint: disable=too-many-locals

        ui = bui.app.ui_v1

        # A simple number standing in for actual data (to show how we'd
        # save/restore actual data).
        self._dummy_data = dummy_data

        # We want to display differently whether we're an auxiliary
        # window or not, but unfortunately that value is not yet
        # available until we're added to the main-window-stack so it
        # must be explicitly passed in.
        self._auxiliary_style = auxiliary_style

        # Calc scale and size for our backing window. For medium & large
        # ui-scale we aim for a window small enough to always be fully
        # visible on-screen and for small mode we aim for a window big
        # enough that we never see the window edges; only the window
        # texture covering the whole screen.
        uiscale = ui.uiscale
        self._width = 1400 if uiscale is bui.UIScale.SMALL else 750
        self._height = 1200 if uiscale is bui.UIScale.SMALL else 500
        scale = (
            1.5
            if uiscale is bui.UIScale.SMALL
            else 1.2 if uiscale is bui.UIScale.MEDIUM else 1.0
        )

        # Do some fancy math to calculate our visible area; this will be
        # limited by the screen size in small mode and our backing size
        # otherwise.
        screensize = bui.get_virtual_screen_size()
        vis_width = min(self._width - 100, screensize[0] / scale)
        vis_height = min(self._height - 100, screensize[1] / scale)
        vis_top = 0.5 * self._height + 0.5 * vis_height
        vis_left = 0.5 * self._width - 0.5 * vis_width

        # Nudge our vis area up a bit when we can see the full backing
        # (visual fudge factor).
        if uiscale is not bui.UIScale.SMALL:
            vis_top += 12.0

        super().__init__(
            root_widget=bui.containerwidget(
                size=(self._width, self._height),
                toolbar_visibility='menu_full',
                toolbar_cancel_button_style=(
                    'close' if auxiliary_style else 'back'
                ),
                scale=scale,
            ),
            transition=transition,
            origin_widget=origin_widget,
            # We respond to screen size changes only at small ui-scale;
            # in other cases we assume our window remains fully visible
            # always (flip to windowed mode and resize the app window to
            # confirm this).
            refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL,
        )

        # Title.
        bui.textwidget(
            parent=self._root_widget,
            position=(self._width * 0.5, vis_top - 20),
            size=(0, 0),
            text=f'Template{self._dummy_data}',
            color=ui.title_color,
            scale=0.9 if uiscale is bui.UIScale.SMALL else 1.0,
            # Make sure we avoid overlapping meters in small mode/etc.
            maxwidth=(130 if uiscale is bui.UIScale.SMALL else 200),
            h_align='center',
            v_align='center',
        )

        # For small UI-scale we use the system back/close button;
        # otherwise we make our own.
        if uiscale is bui.UIScale.SMALL:
            bui.containerwidget(
                edit=self._root_widget, on_cancel_call=self.main_window_back
            )
        else:
            btn = bui.buttonwidget(
                parent=self._root_widget,
                id=f'{self.main_window_id_prefix}|close',
                scale=0.8,
                position=(vis_left - 15, vis_top - 30),
                size=(50, 50) if auxiliary_style else (60, 55),
                extra_touch_border_scale=2.0,
                button_type=None if auxiliary_style else 'backSmall',
                on_activate_call=self.main_window_back,
                autoselect=True,
                label=bui.charstr(
                    bui.SpecialChar.CLOSE
                    if auxiliary_style
                    else bui.SpecialChar.BACK
                ),
            )
            bui.containerwidget(edit=self._root_widget, cancel_button=btn)

        # Show our vis-area bounds (for debugging).
        if bool(True):
            # Skip top-left since its always overlapping back/close
            # buttons.
            if bool(False):
                bui.textwidget(
                    parent=self._root_widget,
                    position=(vis_left, vis_top),
                    size=(0, 0),
                    color=(1, 1, 1, 0.5),
                    scale=0.5,
                    text='TL',
                    h_align='left',
                    v_align='top',
                )
            bui.textwidget(
                parent=self._root_widget,
                position=(vis_left + vis_width, vis_top),
                size=(0, 0),
                color=(1, 1, 1, 0.5),
                scale=0.5,
                text='TR',
                h_align='right',
                v_align='top',
            )
            bui.textwidget(
                parent=self._root_widget,
                position=(vis_left, vis_top - vis_height),
                size=(0, 0),
                color=(1, 1, 1, 0.5),
                scale=0.5,
                text='BL',
                h_align='left',
                v_align='bottom',
            )
            bui.textwidget(
                parent=self._root_widget,
                position=(vis_left + vis_width, vis_top - vis_height),
                size=(0, 0),
                scale=0.5,
                color=(1, 1, 1, 0.5),
                text='BR',
                h_align='right',
                v_align='bottom',
            )

        # Description.
        bui.textwidget(
            parent=self._root_widget,
            position=(self._width * 0.5, vis_top - 100),
            size=(0, 0),
            scale=0.6,
            text=(
                f'Use this class as reference for making'
                f' a well-behaved MainWindow class or for\n'
                'navigating between MainWindows. It lives at'
                f' {self.__module__}.{type(self).__qualname__}.\n'
                f'vis-size=({round(vis_width)}, {round(vis_height)})'
            ),
            h_align='center',
            v_align='center',
        )

        # Make a few buttons to navigate to other MainWindows (simply
        # our same class with random different dummy values).
        button_width = 300
        for i in range(3):
            child_dummy_data = self._dummy_data + (i + 1) * 17
            self._player_profiles_button = btn = bui.buttonwidget(
                parent=self._root_widget,
                id=f'{self.main_window_id_prefix}|button{i + 1}',
                position=(
                    self._width * 0.5 - button_width * 0.5,
                    vis_top - 230 - i * 80,
                ),
                autoselect=True,
                size=(button_width, 60),
                label=f'Template{child_dummy_data}',
                on_activate_call=bui.WeakCall(
                    self._child_press, child_dummy_data
                ),
            )

    def _child_press(self, dummy_data: int) -> None:
        # Navigate to a new one of us.
        self.main_window_replace(
            lambda: TemplateMainWindow(
                auxiliary_style=False, dummy_data=dummy_data
            )
        )

    @override
    def get_main_window_state(self) -> bui.MainWindowState:
        # Support recreating our window for back/refresh purposes.
        cls = type(self)

        # IMPORTANT - Pull values from self HERE; if we do it in the
        # lambda below it'll keep self alive which will lead to
        # 'ui-not-getting-cleaned-up' warnings and memory leaks.
        dummy_data = self._dummy_data
        auxiliary_style = self._auxiliary_style

        return bui.BasicMainWindowState(
            create_call=lambda transition, origin_widget: cls(
                transition=transition,
                origin_widget=origin_widget,
                dummy_data=dummy_data,
                auxiliary_style=auxiliary_style,
            ),
        )

    @override
    def main_window_should_preserve_selection(self) -> bool:
        # If we return True here, the app will reselect the last
        # selected widget when creating a new one of our windows. We
        # just need to make sure all of our selectable widgets have
        # unique ids starting with `self.main_window_id_prefix`.
        return True

    @override
    def get_main_window_shared_state_id(self) -> str | None:
        # Here we return a unique id based on what we're displaying.
        # This means each level will remember its selected button. If we
        # remove this function override we get the default behavior
        # where this state is shared for all instances of our class
        # (thus selecting the second button will go to a new window with
        # the second button already selected).
        return f'template{self._dummy_data}'
