from typing import Optional

import axipy
from axipy import Plugin
from axipy.da import (
    CollectionStyle,
    Feature,
    GeometryType,
    PointFontStyle,
    Style,
    Table,
)
from axipy.gui import view_manager

from ..data_types import NamedSearchPatterns, SearchGroupPatterns, SearchPatterns
from ..widgets.select_by_style_widget import SelectByStyleWidget
from ..widgets.style_widget_interface import SelectByStyleWidgetInterface
from .strategy_base import SelectStrategy


class VectorPointStrategy(SelectStrategy):
    """
    Стратегия выделения для векторных символов из шрифтов (Truetype Symbol)
    """

    def __init__(self, f: Feature, table: Table) -> None:
        super().__init__(f, table)
        self.__symbol = axipy.tr("Символ")
        self.__color = axipy.tr("Цвет")
        self.__size = axipy.tr("Размер")
        self.__background_effects = axipy.tr("Дополнительные эффекты")
        self.__rotation = axipy.tr("Угол поворота")
        # число свойств стиля которые могут изменяться
        self.__geometries = [GeometryType.Point, GeometryType.MultiPoint, GeometryType.GeometryCollection]

    def fill_widget(self, widget: "SelectByStyleWidget"):
        widget.search_geometries = {gtype: True for gtype in self.__geometries}
        widget.search_patterns = NamedSearchPatterns(self.search_patterns(), self.string_pattern_group_key())

    def search_patterns(self) -> SearchPatterns:
        patterns = {self.__symbol, self.__color, self.__size, self.__background_effects, self.__rotation}
        return {pattern: True for pattern in patterns}

    def identify(self, style: Style) -> bool:
        return isinstance(style, PointFontStyle)

    def string_pattern_group_key(self) -> str:
        return "vector_point_key"

    def settings_widget(self, iface: Plugin) -> SelectByStyleWidgetInterface:
        widget = SelectByStyleWidget(view_manager.global_parent, iface)
        widget.put_content_on_top(True)
        self.fill_widget(widget)
        return widget

    def is_supported_style(
        self, target: PointFontStyle, source: PointFontStyle, group_patterns: SearchGroupPatterns
    ) -> bool:
        assert isinstance(target, PointFontStyle)
        assert isinstance(source, PointFontStyle)
        patterns = group_patterns[self.string_pattern_group_key()]
        if patterns[self.__symbol] and source.symbol != target.symbol:
            return False
        if patterns[self.__color] and source.color != target.color:
            return False
        if patterns[self.__size] and source.size != target.size:
            return False
        # шрифт должен всегда совпадать. Поведение аналогично MapInfo.
        if source.font_name != target.font_name:
            return False
        is_same_bg_effects = (
            source.black_border == target.black_border
            and source.bold == target.bold
            and source.has_shadow == target.has_shadow
            and source.white_border == target.white_border
        )
        if patterns[self.__background_effects] and not is_same_bg_effects:
            return False
        if patterns[self.__rotation] and source.rotation != target.rotation:
            return False
        return True

    def extract_style_from_collection(self, collection_style: CollectionStyle) -> Optional[Style]:
        pstyle = collection_style.point
        if pstyle:
            return pstyle.clone()
        return pstyle
