# fastpluggy/core/widgets/categories/input/button_list.py
"""
Unified ButtonListWidget - Using objects directly with render_widget()
"""
from typing import Any, Dict, List, Optional, Union

from fastpluggy.core.widgets import RequestParamsMixin
from fastpluggy.core.widgets.base import AbstractWidget
from fastpluggy.core.widgets.categories.input.button import BaseButtonWidget, AutoLinkWidget, FunctionButtonWidget, \
    ButtonWidget, ButtonWidgetMixin


class ButtonListWidget(AbstractWidget, RequestParamsMixin):
    """
    Unified widget for rendering collections of buttons with flexible layouts and styles.
    Replaces both ButtonGroupWidget and the old ButtonListWidget.
    """

    widget_type = "button_list"

    template_name = "widgets/input/button_list.html.j2"
    macro_name = "render_button_list"
    render_method = "macro"

    category = "input"
    description = "Flexible button collection with multiple layout options"
    icon = "list"

    def __init__(
            self,
            buttons: List[Union[BaseButtonWidget, Dict[str, Any], Any]],
            title: Optional[str] = None,
            layout: str = "horizontal",  # "vertical" or "horizontal"
            style: str = "list",  # "list" (spaced) or "group" (connected Bootstrap btn-group)
            button_size: str = "md",  # "sm", "md", "lg"
            spacing: str = "normal",  # "tight", "normal", "loose" (for list style)
            show_count: bool = False,  # Show button count in title
            responsive: bool = True,  # Enable responsive behavior
            **kwargs
    ):
        super().__init__(**kwargs)
        self.buttons = buttons
        self.title = title
        self.layout = layout
        self.style = style
        self.button_size = button_size
        self.spacing = spacing
        self.show_count = show_count
        self.responsive = responsive

        self.list_classes = ""
        self.display_title = None

    def process(self, item: Optional[Dict[str, Any]] = None, **kwargs) -> None:
        """Process all buttons in the collection and prepare for rendering."""
        processed_buttons = []

        for button in self.buttons:
            try:
                processed_button = self._process_individual_button(button, item, **kwargs)
                if processed_button:
                    if ButtonWidgetMixin.evaluate_condition(condition=processed_button.condition, item=item):
                        processed_buttons.append(processed_button)
            except Exception as e:
                processed_buttons.append(self._create_error_button(button, str(e)))

        self.buttons = processed_buttons
        self.list_classes = self._build_list_classes()
        self.display_title = self._build_display_title()

    def _process_individual_button(
            self,
            button: Union[BaseButtonWidget, Dict[str, Any], Any],
            item: Optional[Dict[str, Any]],
            **kwargs
    ) -> Optional[BaseButtonWidget]:
        """Process an individual button and return the widget object."""
        if isinstance(button, BaseButtonWidget):
            return self._process_widget_button(button, item, **kwargs)
        elif isinstance(button, dict):
            return self._create_button_from_dict(button, item, **kwargs)
        else:
            raise ValueError(f"Unsupported button type: {type(button)}")

    def _process_widget_button(
            self,
            button: BaseButtonWidget,
            item: Optional[Dict[str, Any]],
            **kwargs
    ) -> BaseButtonWidget:
        """Process a widget button object."""
        if hasattr(button, 'request'):
            if 'request' in kwargs:
                button.request = kwargs['request']
            elif self.request:
                button.request = self.request

        self._apply_button_size(button)
        button.process(item=item, **kwargs)
        return button

    def _apply_button_size(self, button: BaseButtonWidget) -> None:
        """Apply consistent button sizing by stripping existing size classes then appending."""
        if self.button_size == 'md' or not hasattr(button, 'css_class'):
            return
        css_class = getattr(button, 'css_class', '')
        if not isinstance(css_class, str):
            return
        parts = [c for c in css_class.split() if c not in ('btn-sm', 'btn-lg')]
        parts.append(f'btn-{self.button_size}')
        button.css_class = ' '.join(parts)

    def _create_button_from_dict(
            self,
            button_config: Dict[str, Any],
            item: Optional[Dict[str, Any]],
            **kwargs
    ) -> BaseButtonWidget:
        """Create a button widget from dictionary configuration."""
        config = dict(button_config)

        if 'css_class' in config:
            self._apply_size_to_css_class(config)

        button_type = config.get('type', 'button')

        if button_type == 'auto_link' or 'route_name' in config:
            button = AutoLinkWidget(**config)
        elif button_type == 'function_button' or 'call' in config:
            button = FunctionButtonWidget(**config)
        else:
            button = ButtonWidget(**config)

        return self._process_widget_button(button, item, **kwargs)

    def _apply_size_to_css_class(self, button_config: Dict[str, Any]) -> None:
        """Apply button size to CSS class in config."""
        if self.button_size != 'md':
            css_class = button_config.get('css_class', '')
            if 'btn-sm' not in css_class and 'btn-lg' not in css_class:
                button_config['css_class'] = f"{css_class} btn-{self.button_size}".strip()

    def _create_error_button(self, original_button: Any, error_message: str) -> BaseButtonWidget:
        """Create an error button when processing fails."""
        error_button = ButtonWidget(
            url='#',
            label=f"Error: {type(original_button).__name__}",
            css_class=f"btn btn-{self.button_size} btn-danger",
            onclick=f"alert('Button processing error: {error_message.replace(chr(39), chr(92) + chr(39))}'); return false;",
            disabled=True
        )
        try:
            error_button.process()
        except Exception:
            error_button.method = 'get'
            error_button.params = {}
        return error_button

    def _build_list_classes(self) -> str:
        """Build CSS classes for the button collection layout."""
        if self.style == "group":
            return self._build_group_classes()
        return self._build_list_classes_internal()

    def _build_group_classes(self) -> str:
        """Build Bootstrap btn-group classes."""
        classes = ["btn-group"]
        if self.layout == "vertical":
            classes.append("btn-group-vertical")
        if self.button_size != "md":
            classes.append(f"btn-group-{self.button_size}")
        return " ".join(classes)

    def _build_list_classes_internal(self) -> str:
        """Build classes for spaced button lists."""
        classes = ["button-list"]

        if self.layout == "horizontal":
            classes.append("d-flex flex-wrap")
        else:  # vertical
            classes.append("gap-1")

        spacing_map = {"tight": "gap-1", "normal": "gap-2", "loose": "gap-3"}
        if self.spacing in spacing_map and self.layout != "vertical":
            classes = [c for c in classes if not c.startswith("gap-")]
            classes.append(spacing_map[self.spacing])

        return " ".join(classes)

    def _build_display_title(self) -> Optional[str]:
        """Build display title with optional button count."""
        if not self.title:
            return None
        if self.show_count:
            return f"{self.title} ({len(self.buttons)})"
        return self.title

    @classmethod
    def create_button_group(
            cls,
            buttons: List[Union[BaseButtonWidget, Dict[str, Any]]],
            orientation: str = "horizontal",
            size: str = "md",
            **kwargs
    ) -> 'ButtonListWidget':
        """Factory method to create Bootstrap button groups (connected buttons)."""
        return cls(
            buttons=buttons,
            style="group",
            layout=orientation,
            button_size=size,
            **kwargs
        )


__all__ = ['ButtonListWidget']
