# Copyright 2021 The Pigweed Authors
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""Functions to create checkboxes for menus and toolbars."""

import sys
from typing import Callable, Iterable, Optional, NamedTuple

from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple
from prompt_toolkit.formatted_text import StyleAndTextTuples

_KEY_SEPARATOR = ' '
_CHECKED_BOX = '[✓]'

if sys.platform in ['win32']:
    _CHECKED_BOX = '[x]'


class ToolbarButton(NamedTuple):
    key: Optional[str] = None
    description: Optional[str] = 'Button'
    mouse_handler: Optional[Callable] = None
    is_checkbox: bool = False
    checked: Optional[Callable] = None


def to_checkbox(
    checked: bool,
    mouse_handler: Optional[Callable] = None,
    end: str = ' ',
    unchecked_style: str = 'class:checkbox',
    checked_style: str = 'class:checkbox-checked',
) -> OneStyleAndTextTuple:
    text = _CHECKED_BOX if checked else '[ ]'
    text += end
    style = checked_style if checked else unchecked_style
    if mouse_handler:
        return (style, text, mouse_handler)
    return (style, text)


def to_checkbox_text(checked: bool, end=' '):
    return to_checkbox(checked, end=end)[1]


def to_setting(
    checked: bool,
    text: str,
    active_style='class:toolbar-setting-active',
    inactive_style='',
    mouse_handler=None,
):
    """Apply a style to text if checked is True."""
    style = active_style if checked else inactive_style
    if mouse_handler:
        return (style, text, mouse_handler)
    return (style, text)


def to_checkbox_with_keybind_indicator(
    checked: bool,
    key: str,
    description: str,
    mouse_handler=None,
    base_style: str = '',
    **checkbox_kwargs,
):
    """Create a clickable keybind indicator with checkbox for toolbars."""
    if mouse_handler:
        return to_keybind_indicator(key,
                                    description,
                                    mouse_handler,
                                    leading_fragments=[
                                        to_checkbox(checked, mouse_handler,
                                                    **checkbox_kwargs)
                                    ],
                                    base_style=base_style)
    return to_keybind_indicator(
        key,
        description,
        leading_fragments=[to_checkbox(checked, **checkbox_kwargs)],
        base_style=base_style)


def to_keybind_indicator(
    key: str,
    description: str,
    mouse_handler: Optional[Callable] = None,
    leading_fragments: Optional[Iterable] = None,
    middle_fragments: Optional[Iterable] = None,
    base_style: str = '',
    key_style: str = 'class:keybind',
    description_style: str = 'class:keyhelp',
):
    """Create a clickable keybind indicator for toolbars."""
    if base_style:
        base_style += ' '

    fragments: StyleAndTextTuples = []
    fragments.append((base_style + 'class:toolbar-button-decoration', ' '))

    def append_fragment_with_base_style(frag_list, fragment) -> None:
        if mouse_handler:
            frag_list.append(
                (base_style + fragment[0], fragment[1], mouse_handler))
        else:
            frag_list.append((base_style + fragment[0], fragment[1]))

    # Add any starting fragments first
    if leading_fragments:
        for fragment in leading_fragments:
            append_fragment_with_base_style(fragments, fragment)

    # Function name
    if mouse_handler:
        fragments.append(
            (base_style + description_style, description, mouse_handler))
    else:
        fragments.append((base_style + description_style, description))

    if middle_fragments:
        for fragment in middle_fragments:
            append_fragment_with_base_style(fragments, fragment)

    # Separator and keybind
    if key:
        if mouse_handler:
            fragments.append((base_style + description_style, _KEY_SEPARATOR,
                              mouse_handler))
            fragments.append((base_style + key_style, key, mouse_handler))
        else:
            fragments.append((base_style + description_style, _KEY_SEPARATOR))
            fragments.append((base_style + key_style, key))

    fragments.append((base_style + 'class:toolbar-button-decoration', ' '))
    return fragments
