from typing import Optional, Union

from flet.controls.adaptive_control import AdaptiveControl
from flet.controls.base_control import control
from flet.controls.buttons import ButtonStyle
from flet.controls.control import Control
from flet.controls.control_event import ControlEventHandler
from flet.controls.icon_data import IconData
from flet.controls.layout_control import LayoutControl
from flet.controls.types import (
    ClipBehavior,
    ColorValue,
    IconDataOrControl,
    StrOrControl,
    Url,
)
from flet.utils.validation import V, ValidationRules

__all__ = ["OutlinedButton"]


@control("OutlinedButton")
class OutlinedButton(LayoutControl, AdaptiveControl):
    """
    Outlined buttons are medium-emphasis buttons. They contain actions that are \
    important, but aren't the primary action in an app. Outlined buttons pair well \
    with filled buttons to indicate an alternative, secondary action.

    Example:
    ```python
    ft.OutlinedButton(content="Outlined button")
    ```
    """

    content: Optional[StrOrControl] = None
    """
    A Control representing custom button content.

    Raises:
        ValueError: If neither :attr:`icon` nor `content` is provided.
    """

    icon: Optional[IconDataOrControl] = None
    """
    An icon to display in this button.
    """

    icon_color: Optional[ColorValue] = None
    """
    Icon color.
    """

    style: Optional[ButtonStyle] = None
    """
    """

    autofocus: bool = False
    """
    True if the control will be selected as the initial focus.

    If there is more than one control on a page with autofocus set, then the first one
    added to the page will get focus.
    """

    clip_behavior: ClipBehavior = ClipBehavior.NONE
    """
    The content will be clipped (or not) according to this option.
    """

    url: Optional[Union[str, Url]] = None
    """
    The URL to open when this button is clicked.

    Additionally, if :attr:`on_click` event callback is
    provided, it is fired after that.
    """

    on_click: Optional[ControlEventHandler["OutlinedButton"]] = None
    """
    Called when a user clicks this button.
    """

    on_long_press: Optional[ControlEventHandler["OutlinedButton"]] = None
    """
    Called when this button is long-pressed.
    """

    on_hover: Optional[ControlEventHandler["OutlinedButton"]] = None
    """
    Called when a mouse pointer enters or exists this button's response area.

    `data` property of event object contains `true` (string) when cursor enters and
    `false` when it exits.
    """

    on_focus: Optional[ControlEventHandler["OutlinedButton"]] = None
    """
    Called when this button has received focus.
    """

    on_blur: Optional[ControlEventHandler["OutlinedButton"]] = None
    """
    Called when this button has lost focus.
    """

    __validation_rules__: ValidationRules = (
        V.ensure(
            lambda ctrl: (
                (
                    isinstance(ctrl.icon, IconData)
                    or (isinstance(ctrl.icon, Control) and ctrl.icon.visible)
                )
                or (
                    isinstance(ctrl.content, str)
                    or (isinstance(ctrl.content, Control) and ctrl.content.visible)
                )
            ),
            message="at minimum, icon or content (string or visible Control) "
            "must be provided",
        ),
    )

    async def focus(self):
        """Requests focus for this control."""
        await self._invoke_method("focus")
