"""A text editor that automatically upload file to gitlab at drop"""

# standard
import tempfile
from pathlib import Path

# PyQGIS
from qgis.core import QgsApplication
from qgis.gui import QgsGui
from qgis.PyQt.QtCore import QMimeData
from qgis.PyQt.QtGui import QIcon, QImage, QPixmap
from qgis.PyQt.QtWidgets import QAction, QFileDialog, QWidget
from qgis.utils import iface

# project
from oslandia.gitlab_api.upload import UploadRequestManager
from oslandia.gui.auto_resizing_text_edit import AutoResizingTextEdit
from oslandia.gui.screenshot_maker import take_screenshot
from oslandia.toolbelt.preferences import PlgOptionsManager
from oslandia.toolbelt.qt_utils import (
    _get_local_files_from_mimedata,
    current_datetime_str,
)


class GitLabTextEdit(AutoResizingTextEdit):
    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)

        self._project_id = None
        self.setAcceptDrops(True)

        self._insert_separator_in_edit_action()
        attach_file_action = QAction(
            QIcon(QgsApplication.iconPath("mActionEditInsertLink.svg")),
            self.tr("Attach file"),
        )
        attach_file_action.setToolTip(self.tr("Attach file or image."))
        attach_file_action.triggered.connect(self._insert_file)
        self._edit_actions.append(attach_file_action)

        canvas_screenshot_action = QAction(
            QgsApplication.getThemeIcon("mActionSaveMapAsImage.svg"),
            self.tr("Canvas screenshot."),
        )
        canvas_screenshot_action.setToolTip(self.tr("Canvas screenshot."))
        canvas_screenshot_action.triggered.connect(self._canvas_screenshot)
        self._edit_actions.append(canvas_screenshot_action)

        self.take_screenshot_action = QAction(
            QIcon(":images/themes/default/propertyicons/overlay.svg"),
            self.tr("Take screenshot."),
        )
        self.take_screenshot_action.setToolTip(self.tr("Take screenshot."))
        self.take_screenshot_action.triggered.connect(self._take_screenshot)
        self._edit_actions.append(self.take_screenshot_action)

        self.update_with_plg_settings()

        instance_gui = QgsGui.instance()
        instance_gui.optionsChanged.connect(self.update_with_plg_settings)

    def _insert_file(self) -> None:
        """Select file and insert to edit widget"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, self.tr("Select file to upload")
        )
        if file_path:
            self.insert_file(file_path)

    def _canvas_screenshot(self) -> None:
        """Print current canvas to QPixmap and insert it"""
        canvas = iface.mapCanvas()
        if canvas:
            tmp_path = self._temp_file_name(".png")
            canvas.saveAsImage(str(tmp_path))
            self.insert_file(
                tmp_path,
                self.tr("QGIS canvas added {}").format(current_datetime_str("long")),
            )

    def _take_screenshot(self) -> None:
        """Take a screenshot from user selection and insert it"""
        pixmap = take_screenshot()
        if pixmap:
            self._insert_pixmap(
                pixmap,
                self.tr("Screenshot added {}").format(current_datetime_str("long")),
            )

    @staticmethod
    def _temp_file_name(suffix: str) -> Path:
        """Return temporary file name. File is closed to be used by Qt

        :param suffix: filename suffix
        :type suffix: str
        :return: temporary file name
        :rtype: Path
        """
        # Create temporary file
        tmp_file = tempfile.NamedTemporaryFile(suffix=suffix, delete=False)
        tmp_path = tmp_file.name
        # We are only using tempfile.NamedTemporaryFile to get a temp file path
        # Need to close to be able to save screenshot
        tmp_file.close()
        return Path(tmp_path)

    def _insert_pixmap(self, pixmap: QPixmap, insert_text: str | None) -> None:
        """Insert pixmap as file

        :param pixmap: pixmap
        :type pixmap: QPixmap
        :param insert_text: text to insert before pixmap (optional)
        :type insert_text: Optional[str]
        """
        tmp_path = self._temp_file_name(".png")
        pixmap.save(str(tmp_path), "png")
        self.insert_file(Path(tmp_path), insert_text)

    def set_project_id(self, _project_id: int) -> None:
        """Define project_id needed for image displau

        :param _project_id: project id
        :type _project_id: int
        """
        self._project_id = _project_id

    def insertFromMimeData(self, source: QMimeData | None) -> None:
        """Override insertFromMimeData to paste files or images

        :param source: mime data to import
        :type source: Optional[QMimeData]
        """
        # No override if no project defined, we can't add files or images
        if not self._project_id:
            super().insertFromMimeData(source)

        # Add mimedata if files or images
        source_inserted = False
        if source:
            if source.hasUrls():
                file_paths = _get_local_files_from_mimedata(source)
                for path in file_paths:
                    source_inserted = True
                    self.insert_file(path)
            if source.hasImage():
                source_inserted = True
                image: QImage = source.imageData()
                self._insert_pixmap(
                    QPixmap.fromImage(image),
                    self.tr("Image added {}").format(current_datetime_str("long")),
                )
        if not source_inserted:
            super().insertFromMimeData(source)

    def canInsertFromMimeData(self, source: QMimeData | None) -> bool:
        """Override canInsertFromMimeData to enable action for paste of files or images

        :param source: _description_
        :type source: Optional[QMimeData]
        :return: True if mimedata can be inserted, False otherwise
        :rtype: bool
        """
        # No override if no project defined, we can't add files or images
        if not self._project_id:
            return super().canInsertFromMimeData(source)

        if source:
            if source.hasUrls() and len(_get_local_files_from_mimedata(source)) != 0:
                return True
            if source.hasImage():
                return True
        return super().canInsertFromMimeData(source)

    def insert_file(self, file_path: Path, insert_text: str | None = None) -> None:
        """Insert file in document.
        Upload file to project and insert markdown string

        :param file_path: file path
        :type file_path: Path
        :param insert_text: text to insert before file (optional)
        :type insert_text: Optional[str]
        """
        if not self._project_id:
            return
        manager = UploadRequestManager()
        md_str = manager.create_upload(self._project_id, file_path)
        if md_str:
            if insert_text:
                self.textCursor().insertText(insert_text)
                self.textCursor().insertText("\n\n")

            self.textCursor().insertText(md_str)
            self.textCursor().insertText("\n")

    def update_with_plg_settings(self) -> None:
        """Force update of widget with new plugin settings
        Enable user selection screenshot action from settings
        """
        plg_settings = PlgOptionsManager()
        settings = plg_settings.get_plg_settings()

        # Enable user selection screenshot from settings
        self.take_screenshot_action.setVisible(
            settings.enable_user_selection_screenshot
        )
