"""Widget for text display with preview option"""

# standard
from pathlib import Path
from typing import TYPE_CHECKING

# PyQGIS
from qgis.gui import QgsGui
from qgis.PyQt import QtCore, uic
from qgis.PyQt.QtCore import QSize
from qgis.PyQt.QtWidgets import QToolBar, QWidget

from oslandia.gui.stylesheet import WidgetStyleSheet
from oslandia.helpdesk.markdown import (
    MarkdownRequestManager,
    strip_markdown_html_comments,
)
from oslandia.helpdesk.project import Project, ProjectRequestManager
from oslandia.toolbelt.preferences import PlgOptionsManager


if TYPE_CHECKING:
    from oslandia.gui.helpdesk.gitlab_text_browser import GitLabTextBrowser
    from oslandia.gui.helpdesk.gitlab_text_edit import GitLabTextEdit


class TextEditPreviewWidget(WidgetStyleSheet):
    """QWidget to display text with a preview option

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

    # Signal to indicate changes in issue displayed
    qsig_text_changed = QtCore.pyqtSignal()

    def __init__(self, parent: QWidget | None = None) -> None:
        """Initialize the widget.

        :param parent: parent widget, defaults to None
        :type parent: QWidget | None, optional
        """
        super().__init__(parent)
        uic.loadUi(Path(__file__).parent / f"{Path(__file__).stem}.ui", self)

        # helpful type hints stubs
        self.txt_edit: GitLabTextEdit
        self.txt_preview: GitLabTextBrowser

        # buttons customizations
        self.btn_switch.clicked.connect(self._switch_mode)
        self.btn_switch.setText(self.tr("Preview"))

        self.txt_edit.textChanged.connect(self.qsig_text_changed.emit)

        self.txt_edit.setVisible(True)
        self.txt_preview.setVisible(False)

        # Add toolbar for edition
        self.edit_toolbar = QToolBar(self)
        self.edit_toolbar.setObjectName("OslandiaTextEditorToolbar")
        self.edit_toolbar.setIconSize(QSize(16, 16))
        self.lyt_toolbar.addWidget(self.edit_toolbar)

        for action in self.txt_edit.get_edit_actions():
            action.setToolTip(action.text())
            self.edit_toolbar.addAction(action)

        self.project_id: int | None = None
        self.project: Project | None = None

        instance_gui: QgsGui | None = QgsGui.instance()
        if isinstance(instance_gui, QgsGui):
            instance_gui.optionsChanged.connect(self.update_plg_settings)

    def set_project_id(self, project_id: int) -> None:
        """Define project id, needed form upload download

        :param project_id: project id
        :type project_id: int
        """
        # Set to None current project if id has changed
        if self.project_id != project_id:
            self.project = None
        self.project_id = project_id
        self.txt_preview.set_project_id(project_id)
        self.txt_edit.set_project_id(project_id)

    def _switch_mode(self) -> None:
        """Switch current mode"""
        if self.txt_preview.isVisible():
            self.btn_switch.setText(self.tr("Preview"))
            self.txt_edit.setVisible(True)
            self.frm_edit_toolbar.setVisible(True)
            self.txt_preview.setVisible(False)
        else:
            self.btn_switch.setText(self.tr("Edit"))
            self.txt_edit.setVisible(False)
            self.frm_edit_toolbar.setVisible(False)
            self.txt_preview.setVisible(True)
            plain_text = self.toPlainText()

            if PlgOptionsManager().get_plg_settings().use_gitlab_markdown_api:
                self.txt_preview.setHtml(self.convert_markdown_to_html(plain_text))
            else:
                self.txt_preview.setMarkdown(
                    strip_markdown_html_comments(plain_text) or ""
                )

    def setText(self, text: str) -> None:  # noqa: N802
        """Set text displayed

        :param text: text displayed
        :type text: str
        """
        self.txt_edit.setPlainText(text)
        if PlgOptionsManager().get_plg_settings().use_gitlab_markdown_api:
            self.txt_preview.setHtml(self.convert_markdown_to_html(text))
        else:
            self.txt_preview.setMarkdown(strip_markdown_html_comments(text) or "")

    def convert_markdown_to_html(self, text: str) -> str:
        """Convert markdown to html with lazy image fix if needed

        :param text: markdown text
        :type text: str
        :return: markdown converted as html
        :rtype: str
        """
        manager = MarkdownRequestManager()

        project_path = None
        if self.project is None and self.project_id is not None:
            # Get the project to be able to use project path for markdown render
            project_manager = ProjectRequestManager()
            self.project = project_manager.get_project(project_id=self.project_id)
        if self.project is not None:
            project_path = self.project.full_path

        html = manager.convert_markdown_to_html(text, project_path)
        if html is None:
            return strip_markdown_html_comments(text) or ""
        if PlgOptionsManager().get_plg_settings().use_gitlab_markdown_format:
            return MarkdownRequestManager.fix_gitlab_flavor_lazy_images(html)
        return html

    def update_plg_settings(self) -> None:
        """Force refresh of text with current plugin settings"""
        self.setText(self.toPlainText())

    def toPlainText(self) -> str:  # noqa: N802
        """Get edit plain text

        :return: edit plain text
        :rtype: str
        """
        return self.txt_edit.toPlainText()

    def setReadOnly(self, read_only: bool = True) -> None:  # noqa: N802
        """Disable / Enable edition of text

        :param read_only: True to disable edition, Falst to enable edition, defaults to True
        :type read_only: bool, optional
        """
        self.frm_buttons.setVisible(not read_only)
        self.txt_edit.setVisible(not read_only)
        self.txt_preview.setVisible(read_only)
        self.btn_switch.setText(self.tr("Edit") if read_only else self.tr("Preview"))

        # Display value for preview
        self.setText(self.toPlainText())

    def setPlaceholderText(self, text: str) -> None:  # noqa: N802
        """Define text edit place holder text

        :param text: place holder text
        :type text: str
        """
        self.txt_edit.setPlaceholderText(text)

    def clear(self) -> None:
        """Clear current content"""
        self.txt_edit.clear()
        self.txt_preview.clear()
