# Released under the MIT License. See LICENSE for details.
#
"""UIs for debugging purposes."""

from __future__ import annotations

import logging
from typing import cast, override

import bauiv1 as bui
import bascenev1 as bs


class BenchmarksAndStressTestsWindow(bui.MainWindow):
    """Window for launching benchmarks or stress tests."""

    def __init__(
        self,
        transition: str | None = 'in_right',
        origin_widget: bui.Widget | None = None,
    ):
        # pylint: disable=too-many-locals
        # pylint: disable=too-many-statements
        # pylint: disable=cyclic-import
        from bauiv1lib import popup

        uiscale = bui.app.ui_v1.uiscale
        self._width = width = 1200 if uiscale is bui.UIScale.SMALL else 580
        self._height = height = (
            900
            if uiscale is bui.UIScale.SMALL
            else 420 if uiscale is bui.UIScale.MEDIUM else 520
        )

        self._stress_test_game_type = 'Random'
        self._stress_test_playlist = '__default__'
        self._stress_test_player_count = 8
        self._stress_test_round_duration = 30

        # Do some fancy math to fill all available screen area up to the
        # size of our backing container. This lets us fit to the exact
        # screen shape at small ui scale.
        screensize = bui.get_virtual_screen_size()
        scale = (
            2.32
            if uiscale is bui.UIScale.SMALL
            else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
        )
        # Calc screen size in our local container space and clamp to a
        # bit smaller than our container size.
        target_width = min(self._width - 70, screensize[0] / scale)
        target_height = min(self._height - 70, screensize[1] / scale)

        # To get top/left coords, go to the center of our window and
        # offset by half the width/height of our target area.
        yoffs = 0.5 * self._height + 0.5 * target_height + 30.0

        self._scroll_width = target_width
        self._scroll_height = target_height - 31
        self._scroll_bottom = yoffs - 60 - self._scroll_height

        self._sub_width = min(510.0, self._scroll_width)
        self._sub_height = 520

        self._r = 'debugWindow'
        uiscale = bui.app.ui_v1.uiscale
        super().__init__(
            root_widget=bui.containerwidget(
                size=(width, height),
                scale=scale,
                toolbar_visibility=(
                    'menu_minimal'
                    if uiscale is bui.UIScale.SMALL
                    else 'menu_full'
                ),
            ),
            transition=transition,
            origin_widget=origin_widget,
            # We're affected by screen size only at small ui-scale.
            refresh_on_screen_size_changes=uiscale is bui.UIScale.SMALL,
        )

        if bui.app.ui_v1.uiscale is bui.UIScale.SMALL:
            bui.containerwidget(
                edit=self._root_widget, on_cancel_call=self.main_window_back
            )
            self._back_button = bui.get_special_widget('back_button')
        else:
            self._back_button = btn = bui.buttonwidget(
                parent=self._root_widget,
                id=f'{self.main_window_id_prefix}|back',
                position=(40, yoffs - 53),
                size=(60, 60),
                scale=0.8,
                autoselect=True,
                label=bui.charstr(bui.SpecialChar.BACK),
                button_type='backSmall',
                on_activate_call=self.main_window_back,
            )
            bui.containerwidget(edit=self._root_widget, cancel_button=btn)

        bui.textwidget(
            parent=self._root_widget,
            position=(
                self._width * 0.5,
                yoffs - (45 if uiscale is bui.UIScale.SMALL else 30),
            ),
            size=(0, 0),
            maxwidth=360,
            scale=0.8 if uiscale is bui.UIScale.SMALL else 1.0,
            text=bui.Lstr(resource=f'{self._r}.titleText'),
            h_align='center',
            v_align='center',
            color=bui.app.ui_v1.title_color,
        )

        self._scrollwidget = bui.scrollwidget(
            parent=self._root_widget,
            highlight=False,
            size=(self._scroll_width, self._scroll_height),
            position=(
                self._width * 0.5 - self._scroll_width * 0.5,
                self._scroll_bottom,
            ),
            border_opacity=0.4,
            center_small_content_horizontally=True,
        )
        bui.containerwidget(edit=self._scrollwidget, claims_left_right=True)

        self._subcontainer = bui.containerwidget(
            parent=self._scrollwidget,
            size=(self._sub_width, self._sub_height),
            background=False,
        )

        v = self._sub_height - 70
        button_width = 300
        btn = bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|cpu',
            position=((self._sub_width - button_width) * 0.5, v),
            size=(button_width, 60),
            autoselect=True,
            label=bui.Lstr(resource=f'{self._r}.runCPUBenchmarkText'),
            on_activate_call=self._run_cpu_benchmark_pressed,
        )
        bui.widget(
            edit=btn, up_widget=self._back_button, left_widget=self._back_button
        )
        v -= 60

        bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|mediareload',
            position=((self._sub_width - button_width) * 0.5, v),
            size=(button_width, 60),
            autoselect=True,
            label=bui.Lstr(resource=f'{self._r}.runMediaReloadBenchmarkText'),
            on_activate_call=self._run_media_reload_benchmark_pressed,
        )
        v -= 60

        bui.textwidget(
            parent=self._subcontainer,
            position=(self._sub_width * 0.5, v + 22),
            size=(0, 0),
            text=bui.Lstr(resource=f'{self._r}.stressTestTitleText'),
            maxwidth=200,
            color=bui.app.ui_v1.heading_color,
            scale=0.85,
            h_align='center',
            v_align='center',
        )
        v -= 45

        x_offs = 165
        bui.textwidget(
            parent=self._subcontainer,
            position=(x_offs - 10, v + 22),
            size=(0, 0),
            text=bui.Lstr(resource=f'{self._r}.stressTestPlaylistTypeText'),
            maxwidth=130,
            color=bui.app.ui_v1.heading_color,
            scale=0.65,
            h_align='right',
            v_align='center',
        )

        popup.PopupMenu(
            parent=self._subcontainer,
            button_id=f'{self.main_window_id_prefix}|playlisttype',
            position=(x_offs, v),
            width=150,
            choices=['Random', 'Teams', 'Free-For-All'],
            choices_display=[
                bui.Lstr(resource=a)
                for a in [
                    'randomText',
                    'playModes.teamsText',
                    'playModes.freeForAllText',
                ]
            ],
            current_choice='Auto',
            on_value_change_call=self._stress_test_game_type_selected,
        )

        v -= 46
        bui.textwidget(
            parent=self._subcontainer,
            position=(x_offs - 10, v + 22),
            size=(0, 0),
            text=bui.Lstr(resource=f'{self._r}.stressTestPlaylistNameText'),
            maxwidth=130,
            color=bui.app.ui_v1.heading_color,
            scale=0.65,
            h_align='right',
            v_align='center',
        )

        self._stress_test_playlist_name_field = bui.textwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|playlistname',
            position=(x_offs + 5, v - 5),
            size=(250, 46),
            text=self._stress_test_playlist,
            h_align='left',
            v_align='center',
            autoselect=True,
            color=(0.9, 0.9, 0.9, 1.0),
            description=bui.Lstr(
                resource=f'{self._r}.stressTestPlaylistDescriptionText'
            ),
            editable=True,
            padding=4,
        )
        v -= 29
        x_sub = 60

        # Player count.
        bui.textwidget(
            parent=self._subcontainer,
            position=(x_offs - 10, v),
            size=(0, 0),
            text=bui.Lstr(resource=f'{self._r}.stressTestPlayerCountText'),
            color=(0.8, 0.8, 0.8, 1.0),
            h_align='right',
            v_align='center',
            scale=0.65,
            maxwidth=130,
        )
        self._stress_test_player_count_text = bui.textwidget(
            parent=self._subcontainer,
            position=(246 - x_sub, v - 14),
            size=(60, 28),
            editable=False,
            color=(0.3, 1.0, 0.3, 1.0),
            h_align='right',
            v_align='center',
            text=str(self._stress_test_player_count),
            padding=2,
        )
        bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|pdec',
            position=(330 - x_sub, v - 11),
            size=(28, 28),
            label='-',
            autoselect=True,
            on_activate_call=bui.CallStrict(
                self._stress_test_player_count_decrement
            ),
            repeat=True,
            enable_sound=True,
        )
        bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|pinc',
            position=(380 - x_sub, v - 11),
            size=(28, 28),
            label='+',
            autoselect=True,
            on_activate_call=bui.CallStrict(
                self._stress_test_player_count_increment
            ),
            repeat=True,
            enable_sound=True,
        )
        v -= 42

        # Round duration.
        bui.textwidget(
            parent=self._subcontainer,
            position=(x_offs - 10, v),
            size=(0, 0),
            text=bui.Lstr(resource=f'{self._r}.stressTestRoundDurationText'),
            color=(0.8, 0.8, 0.8, 1.0),
            h_align='right',
            v_align='center',
            scale=0.65,
            maxwidth=130,
        )
        self._stress_test_round_duration_text = bui.textwidget(
            parent=self._subcontainer,
            position=(246 - x_sub, v - 14),
            size=(60, 28),
            editable=False,
            color=(0.3, 1.0, 0.3, 1.0),
            h_align='right',
            v_align='center',
            text=str(self._stress_test_round_duration),
            padding=2,
        )
        bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|rdurdec',
            position=(330 - x_sub, v - 11),
            size=(28, 28),
            label='-',
            autoselect=True,
            on_activate_call=bui.CallStrict(
                self._stress_test_round_duration_decrement
            ),
            repeat=True,
            enable_sound=True,
        )
        bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|rdurinc',
            position=(380 - x_sub, v - 11),
            size=(28, 28),
            label='+',
            autoselect=True,
            on_activate_call=bui.CallStrict(
                self._stress_test_round_duration_increment
            ),
            repeat=True,
            enable_sound=True,
        )
        v -= 82
        btn = bui.buttonwidget(
            parent=self._subcontainer,
            id=f'{self.main_window_id_prefix}|runstress',
            position=((self._sub_width - button_width) * 0.5, v),
            size=(button_width, 60),
            autoselect=True,
            label=bui.Lstr(resource=f'{self._r}.runStressTestText'),
            on_activate_call=self._stress_test_pressed,
        )
        bui.widget(edit=btn, show_buffer_bottom=50)

    @override
    def get_main_window_state(self) -> bui.MainWindowState:
        # Support recreating our window for back/refresh purposes.
        cls = type(self)
        return bui.BasicMainWindowState(
            create_call=lambda transition, origin_widget: cls(
                transition=transition, origin_widget=origin_widget
            )
        )

    @override
    def main_window_should_preserve_selection(self) -> bool:
        return True

    def _stress_test_player_count_decrement(self) -> None:
        self._stress_test_player_count = max(
            1, self._stress_test_player_count - 1
        )
        bui.textwidget(
            edit=self._stress_test_player_count_text,
            text=str(self._stress_test_player_count),
        )

    def _stress_test_player_count_increment(self) -> None:
        self._stress_test_player_count = self._stress_test_player_count + 1
        bui.textwidget(
            edit=self._stress_test_player_count_text,
            text=str(self._stress_test_player_count),
        )

    def _stress_test_round_duration_decrement(self) -> None:
        self._stress_test_round_duration = max(
            10, self._stress_test_round_duration - 10
        )
        bui.textwidget(
            edit=self._stress_test_round_duration_text,
            text=str(self._stress_test_round_duration),
        )

    def _stress_test_round_duration_increment(self) -> None:
        self._stress_test_round_duration = self._stress_test_round_duration + 10
        bui.textwidget(
            edit=self._stress_test_round_duration_text,
            text=str(self._stress_test_round_duration),
        )

    def _stress_test_game_type_selected(self, game_type: str) -> None:
        self._stress_test_game_type = game_type

    def _run_cpu_benchmark_pressed(self) -> None:
        if bui.app.classic is None:
            logging.warning('run-cpu-benchmark requires classic')
            return
        bui.app.classic.run_cpu_benchmark()

    def _run_media_reload_benchmark_pressed(self) -> None:
        if bui.app.classic is None:
            logging.warning('run-media-reload-benchmark requires classic')
            return
        bui.app.classic.run_media_reload_benchmark()

    def _stress_test_pressed(self) -> None:
        from bascenev1lib.mainmenu import MainMenuActivity

        if bui.app.classic is None:
            logging.warning('stress-test requires classic')
            return

        activity = bs.get_foreground_host_activity()
        if isinstance(activity, MainMenuActivity):
            bui.app.classic.run_stress_test(
                playlist_type=self._stress_test_game_type,
                playlist_name=cast(
                    str,
                    bui.textwidget(query=self._stress_test_playlist_name_field),
                ),
                player_count=self._stress_test_player_count,
                round_duration=self._stress_test_round_duration,
            )
            bui.containerwidget(edit=self._root_widget, transition='out_right')
        else:
            bui.screenmessage(
                bui.Lstr(value='Already present in another activity.')
            )
