"""Widget for plugin display"""

# standard
from functools import partial
from pathlib import Path

# PyQGIS
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QSize, Qt
from qgis.PyQt.QtGui import QCursor, QIcon, QMouseEvent
from qgis.PyQt.QtWidgets import QToolButton, QWidget

# Project
from oslandia.__about__ import DIR_PLUGIN_ROOT
from oslandia.constants import UTM_CONTENT_SHOWCASE
from oslandia.datamodels.mdl_projects_browser import ProjectObj
from oslandia.gui.showcase.dlg_click_cards_project import ClickCardProjectDialog
from oslandia.gui.stylesheet import WidgetStyleSheet
from oslandia.showcase.showcase_manager import ShowcaseManager
from oslandia.toolbelt.network_manager import open_url_in_browser
from oslandia.toolbelt.qgis_info import get_qgis_language
from oslandia.toolbelt.qgis_plugins_handling import is_installed_plugin


class ProjectCardsWidget(WidgetStyleSheet):
    """QWidget to display plugins or product on Oslandia Browser

    :param parent: dialog parent, defaults to None
    :type parent: Optional[QWidget], optional
    """

    def __init__(
        self, parent: QWidget | None = None, tooltip_text: str | None = None
    ) -> None:
        super().__init__(parent)
        ui_path = Path(__file__).resolve(True).parent / "wdg_cards_project.ui"
        uic.loadUi(ui_path, self)
        self.button_style()
        self.setToolTip(tooltip_text)
        self.ribbon_installed.setVisible(False)
        self.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
        self.url_on_click = None
        self.project: ProjectObj | None = None

    def display_ribbon_installed(self) -> None:
        """Display a small ribbon "installed" """
        self.ribbon_installed.setVisible(True)
        self.ribbon_installed.setText(self.tr("Installed"))
        self.ribbon_installed.setStyleSheet(
            "QLabel {"
            "    background-color: #28a745; "
            "    color: white; "
            "    font: bold 11px; "
            "    padding: 1px 4px; "
            "    border-radius: 2px; "
            "}"
        )
        self.ribbon_installed.setMinimumHeight(20)
        self.ribbon_installed.setMaximumHeight(20)

    def set_display_data(self, project: ProjectObj) -> None:
        """Display ProjectObj informatio on widget

        :param project: Object containing project information
        :type project: ProjectObj
        """
        self.project = project

        self.set_text_and_font(self.lbl_name, project.name, bold=True, font_size=14)
        self.lbl_logo.setAlignment(Qt.AlignmentFlag.AlignCenter)

        if project.logo:
            icon_path = ShowcaseManager().get_project_icon_path(
                project.name, project.logo
            )
            if icon_path and icon_path.exists():
                logo = QIcon(str(icon_path))
                self.lbl_logo.setPixmap(logo.pixmap(logo.actualSize(QSize(50, 50))))
            else:
                self._set_placeholder_logo()
        else:
            self._set_placeholder_logo()

        self.setup_button_with_url(self.tb_doc, project.doc_url)
        self.setup_button_with_url(self.tb_code, project.code_url)
        self.setup_button_with_url(self.tb_blog, project.blog_link)
        self.setup_button_with_url(self.tb_issue, project.issue_to_be_funded)
        self.set_text_and_font(self.lbl_version, project.version, font_size=8)

        self.lbl_description.setWordWrap(True)
        self.lbl_name.setWordWrap(True)

        # Description
        if get_qgis_language() == "fr" and project.description_fr:
            description = project.description_fr
        else:
            description = project.description_en

        self.lbl_description.setWordWrap(True)
        self.set_text_and_font(
            widget=self.lbl_description, text=description, font_italic=True
        )
        # Ribbon installed
        if is_installed_plugin(project.name, True):
            self.display_ribbon_installed()

    def _set_placeholder_logo(self) -> None:
        """Displays a placeholder icon whilst waiting for the actual logo to download."""
        placeholder = QIcon(
            str(DIR_PLUGIN_ROOT / "resources/images/placeholder_oslandia.svg")
        )
        self.lbl_logo.setPixmap(
            placeholder.pixmap(placeholder.actualSize(QSize(50, 50)))
        )

    def set_icon(self, icon: QIcon) -> None:
        """Updates the logo icon once it has been downloaded, without rebuilding the widget.

        :param icon: icon loaded from the local cache
        :type icon: QIcon
        """
        self.lbl_logo.setPixmap(icon.pixmap(icon.actualSize(QSize(50, 50))))
        self.lbl_logo.setAlignment(Qt.AlignmentFlag.AlignCenter)

    def set_tool_button_icon(self, color: str = "default") -> None:
        """Set tool button icon

        :param color: Button color, default = oslandia_blue, otherwise white, defaults to "default"
        :type color: str, optional
        """
        color_suffix = "" if color == "default" else "_white"
        icons = {
            "tb_code": "repository",
            "tb_doc": "documentation",
            "tb_blog": "article",
            "tb_issue": "ticket",
        }

        for attr, icon_name in icons.items():
            icon_path = (
                DIR_PLUGIN_ROOT / f"resources/images/{icon_name}{color_suffix}.svg"
            )
            getattr(self, attr).setIcon(QIcon(str(icon_path)))

    def button_style(self) -> None:
        """Configures the appearance and behavior of toolbar buttons.

        - Defines button icons.
        - Adds tooltips for each button.
        - Remove button borders.
        - Change cursor to hand pointer to indicate clickability.
        """
        # Icon
        self.set_tool_button_icon()

        buttons = [
            (self.tb_code, "Code repository"),
            (self.tb_doc, "Documentation"),
            (self.tb_blog, "Blog article"),
            (self.tb_issue, "Issue to be funded"),
        ]

        for button, tooltip in buttons:
            button.setToolTip(self.tr(tooltip))
            button.setStyleSheet(
                """
                QToolTip {
                    background-color: black;
                    color: white;
                }
                QToolButton {
                    border: none;
                }
            """
            )
            button.setCursor(Qt.CursorShape.PointingHandCursor)

    def set_text_and_font(
        self,
        widget: QWidget,
        text: str,
        bold: bool = False,
        font_size: int | None = None,
        font_italic: bool = False,
    ) -> None:
        """Sets the text and font properties of a widget, including optional boldness
            and font size adjustments.

        :param widget: The widget to set the text and font on (e.g., QLabel, QPushButton)
        :param text: The text to display in the widget
        :param bold: Whether to apply bold formatting to the font (default: False)
        :param font_size: The size of the font to apply (optional)
        :param font_italic: Whether to apply italic formatting to the font (default: False)
        :return: None
        """

        widget.setText(text)
        if bold or font_size or font_italic:
            font = widget.font()
            if bold:
                font.setBold(True)
            if font_size:
                font.setPointSize(font_size)
            if font_italic:
                font.setItalic(True)
            widget.setFont(font)

    def setup_button_with_url(self, button: QToolButton, url: str) -> None:
        """Configures a QPushButton to open a URL in the default web browser. The
            button is enabled or disabled based on the validity of the URL.

        :param button: Instance of the QPushButton to configure
        :param url: URL to be opened when the button is clicked
        """
        try:
            button.clicked.disconnect()
        except Exception:
            pass
        if url:
            button.setEnabled(True)
        else:
            button.setVisible(False)
            return

        button.clicked.connect(partial(open_url_in_browser, url, UTM_CONTENT_SHOWCASE))

    def mousePressEvent(self, event: QMouseEvent) -> None:  # noqa: N802
        """Event triggered by clicking on the cards"""
        if event.button() == Qt.MouseButton.LeftButton and self.project:
            dialog = ClickCardProjectDialog(project=self.project, parent=self)
            dialog.setProperty("class", "borderless-detail-project")
            dialog.exec()
        super().mousePressEvent(event)
