# Released under the MIT License. See LICENSE for details.
#
"""Provides ConfirmWindow base class and commonly used derivatives."""

from typing import TYPE_CHECKING

import bauiv1 as bui
from bauiv1 import _uiv1assets
from bauiv1 import _commonassets, _classicassets

if TYPE_CHECKING:
    from typing import Any, Callable


class ConfirmWindow:
    """Window for answering simple yes/no questions."""

    def __init__(
        self,
        text: str | bui.Lstr | bui.LangStr | None = None,
        action: Callable[[], Any] | None = None,
        width: float = 360.0,
        height: float = 100.0,
        *,
        cancel_button: bool = True,
        cancel_is_selected: bool = False,
        color: tuple[float, float, float] = (1, 1, 1),
        text_scale: float = 1.0,
        ok_text: str | bui.Lstr | bui.LangStr | None = None,
        cancel_text: str | bui.Lstr | bui.LangStr | None = None,
        origin_widget: bui.Widget | None = None,
        permanent_ok_fade: bool = False,
    ):

        ui = bui.app.ui_v1

        # Make sure our widgets have globally unique ids.
        self._id_prefix = ui.new_id_prefix('confirm')

        if text is None:
            text = _commonassets.strings.status.are_you_sure
        if ok_text is None:
            ok_text = _commonassets.strings.actions.ok
        if cancel_text is None:
            cancel_text = _commonassets.strings.actions.cancel
        height += 40
        width = max(width, 360)
        self._action = action

        self._permanent_ok_fade = permanent_ok_fade

        # If they provided an origin-widget, scale up from that.
        self._transition_out: str | None
        scale_origin: tuple[float, float] | None
        if origin_widget is not None:
            self._transition_out = 'out_scale'
            scale_origin = origin_widget.get_screen_space_center()
            transition = 'in_scale'
        else:
            self._transition_out = None
            scale_origin = None
            transition = 'in_right'

        assert bui.app.classic is not None
        uiscale = bui.app.ui_v1.uiscale
        self.root_widget = bui.containerwidget(
            size=(width, height),
            transition=transition,
            toolbar_visibility='menu_minimal_no_back',
            parent=bui.get_special_widget('overlay_stack'),
            scale=(
                1.9
                if uiscale is bui.UIScale.SMALL
                else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
            ),
            scale_origin_stack_offset=scale_origin,
            darken_behind=True,
        )

        bui.textwidget(
            parent=self.root_widget,
            position=(width * 0.5, height - 5 - (height - 75) * 0.5),
            size=(0, 0),
            h_align='center',
            v_align='center',
            text=text,
            scale=text_scale,
            color=color,
            maxwidth=width * 0.9,
            max_height=height - 75,
        )

        cbtn: bui.Widget | None
        if cancel_button:
            cbtn = btn = bui.buttonwidget(
                parent=self.root_widget,
                id=f'{self._id_prefix}|cancel',
                autoselect=True,
                position=(20, 20),
                size=(150, 50),
                label=cancel_text,
                on_activate_call=self._cancel,
            )
            bui.containerwidget(edit=self.root_widget, cancel_button=btn)
            ok_button_h = width - 175
        else:
            # if they don't want a cancel button, we still want back
            # presses to be able to dismiss the window; just wire it up
            # to do the ok button
            ok_button_h = width * 0.5 - 75
            cbtn = None
        btn = bui.buttonwidget(
            parent=self.root_widget,
            id=f'{self._id_prefix}|ok',
            autoselect=True,
            position=(ok_button_h, 20),
            size=(150, 50),
            label=ok_text,
            on_activate_call=self._ok,
        )

        # if they didn't want a cancel button, we still want to be able
        # to hit cancel/back/etc to dismiss the window
        if not cancel_button:
            bui.containerwidget(
                edit=self.root_widget, on_cancel_call=btn.activate
            )

        bui.containerwidget(
            edit=self.root_widget,
            selected_child=(
                cbtn if cbtn is not None and cancel_is_selected else btn
            ),
            start_button=btn,
        )

    def _cancel(self) -> None:
        bui.containerwidget(
            edit=self.root_widget,
            transition=(
                'out_right'
                if self._transition_out is None
                else self._transition_out
            ),
        )

    def _ok(self) -> None:
        if not self.root_widget:
            return
        bui.containerwidget(
            edit=self.root_widget,
            darken_behind_is_permanent=self._permanent_ok_fade,
            transition=(
                'out_left'
                if self._transition_out is None
                else self._transition_out
            ),
        )
        if self._action is not None:
            self._action()


class QuitWindow:
    """Popup window to confirm quitting."""

    def __init__(
        self,
        quit_type: bui.QuitType | None = None,
        swish: bool = False,
        origin_widget: bui.Widget | None = None,
    ):
        ui = bui.app.ui_v1
        platform = bui.app.env.platform

        self._quit_type = quit_type

        # If there's already one of us up somewhere, kill it.
        if ui.quit_window is not None:
            ui.quit_window.delete()
            ui.quit_window = None
        if swish:
            _uiv1assets.audio.swish.get().play()

        # Generally Macs say Quit and other stuff says Exit
        strs = _classicassets.strings.ui
        confirmstr = (
            strs.quit_app_confirm
            if platform is type(platform).MACOS
            else strs.exit_app_confirm
        )
        quit_text = confirmstr(app_name=strs.app_name)

        self._root_widget = ui.quit_window = ConfirmWindow(
            quit_text,
            lambda: (
                bui.quit(confirm=False, quit_type=self._quit_type)
                if self._quit_type is not None
                else bui.quit(confirm=False)
            ),
            origin_widget=origin_widget,
            # In situations where the quit action will *actually* kill
            # the process, tell the confirm to not fade back in when the
            # confirm button is pressed. It just looks a bit visually
            # odd if the confirm fades back in just before the app fades
            # out to quit.
            permanent_ok_fade=not bui.app.env.supports_soft_quit,
        ).root_widget
