"""Widget for displaying project information."""

# standard
from functools import partial
from pathlib import Path

# PyQGIS
from qgis.PyQt import uic
from qgis.PyQt.QtCore import QSize, Qt, QUrl
from qgis.PyQt.QtGui import QCursor, QIcon, QPixmap
from qgis.PyQt.QtWidgets import QDialog, QLabel, QPushButton, 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.toolbelt.network_manager import NetworkRequestsManager
from oslandia.toolbelt.project_manager import ProjectManager
from oslandia.toolbelt.qgis_info import get_qgis_language


class ProjectWidget(QWidget):
    """QWidget to display plugins or product within Oslandia Browser.

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

    def __init__(self, parent: QWidget | None = None):
        """Class initialization."""
        super().__init__(parent)
        ui_path = Path(__file__).resolve(True).parent / "wdg_project.ui"
        uic.loadUi(ui_path, self)
        self.tb_about.setOpenExternalLinks(True)
        self.tb_description.setOpenExternalLinks(True)
        self.button_style()
        self.list_images = None

    def show_large_image(self, event, name: str, image: QPixmap) -> None:
        """Display a full-size image in a QDialog

        :param name: Name of the windows
        :type name: str
        :param image: Image to display
        :type image: QPixmap
        """

        large_window = QDialog(self)
        large_window.setWindowTitle(name)
        large_label = QLabel(large_window)
        large_label.setPixmap(image)
        large_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        large_window.setFixedSize(image.size())
        large_window.exec()

    def display_project_images(self, project: ProjectObj) -> None:
        """Display screenshots of a project if available.

        :param project: Project object
        :type project: ProjectObj
        """

        self.lbl_image.clear()
        if project.screenshot and project.screenshot != "":
            self.list_images = ProjectManager().get_image_by_project_name(project.name)
            if self.list_images:
                image_path = self.list_images[0]
                if image_path.exists():
                    image = QPixmap(str(image_path))
                    self.lbl_image.setCursor(QCursor(Qt.CursorShape.PointingHandCursor))
                    image_small = image.scaled(
                        600, 300, Qt.AspectRatioMode.KeepAspectRatio
                    )
                    self.lbl_image.setPixmap(image_small)
                    self.lbl_image.setAlignment(Qt.AlignmentFlag.AlignCenter)
                    self.lbl_image.mousePressEvent = lambda event: (
                        self.show_large_image(event, name=project.name, image=image)
                    )

    def set_display_data(self, project: ProjectObj):
        """Display data about a project.

        :param project: project to display
        :type project: ProjectObj
        """

        # Project icon
        if project.logo:
            logo = ProjectManager().get_project_icon(project.name, project.logo)

            self.set_text_and_font(self.lbl_name, project.name, bold=True, font_size=14)
            self.lbl_logo.setPixmap(logo.pixmap(logo.actualSize(QSize(50, 50))))

        # Project images
        self.display_project_images(project)

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

        # Set various text fields (Version, Tags, Funders)
        self.lbl_version.setText(project.version)
        self.lbl_tags.setText(project.tags)
        self.lbl_funders.setText(project.funders)

        # Funders
        self.lbl_funders.setTextFormat(Qt.TextFormat.RichText)
        self.lbl_funders.setWordWrap(True)

        # About / description
        self.tb_description.setTextFormat(Qt.TextFormat.RichText)
        self.tb_description.setWordWrap(True)
        self.tb_description.setText(description)

        self.tb_about.setTextFormat(Qt.TextFormat.RichText)
        self.tb_about.setWordWrap(True)
        self.tb_about.setText(project.about)

        self.setup_button_with_url(self.btn_doc, project.doc_url)
        self.setup_button_with_url(self.btn_repo, project.code_url)
        self.setup_button_with_url(self.btn_blog, project.blog_link)
        self.setup_button_with_url(self.btn_issue, project.issue_to_be_funded)

    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 = {
            "btn_doc": "repository",
            "btn_repo": "documentation",
            "btn_blog": "article",
            "btn_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("white")

        buttons = [
            (self.btn_repo, "Code repository"),
            (self.btn_doc, "Documentation"),
            (self.btn_blog, "Blog article"),
            (self.btn_issue, "Issue to be funded"),
        ]

        for button, tooltip in buttons:
            button.setToolTip(self.tr(tooltip))

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

        :param qlabel_widget: widget to set the text and font on
        :param text: text to display in the widget
        :param bold: whether to apply bold formatting to the font (default: False)
        :param font_size: size of the font to apply (optional)

        :return: None
        """
        qlabel_widget.setText(text)

        if bold or font_size:
            font = qlabel_widget.font()
            if bold:
                font.setBold(True)
            if font_size:
                font.setPointSize(font_size)
            qlabel_widget.setFont(font)

    def setup_button_with_url(self, button: QPushButton, url: str) -> None:
        """Configure 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 TypeError:
            # handle exception raised when button has not connected objects.
            # see: https://www.riverbankcomputing.com/static/Docs/PyQt6/signals_slots.html#disconnect
            # and https://stackoverflow.com/q/21586643/2556577
            pass

        if url:
            button.setEnabled(True)
            button.setStyleSheet(
                "background-color: #3a74ac; color: white; font-weight: bold; "
            )
            button.setCursor(Qt.CursorShape.PointingHandCursor)
        else:
            button.setEnabled(False)
            button.setStyleSheet("background-color: #cbcbcb; color: #555555; ")
            button.setCursor(Qt.CursorShape.ArrowCursor)
            return

        ntwk_manager = NetworkRequestsManager()
        button.clicked.connect(
            partial(ntwk_manager.open_url, QUrl(url), UTM_CONTENT_SHOWCASE)
        )
