"""A text editor that automatically get image from upload and adjust image size with available width"""

# PyQGIS
from qgis.PyQt.QtCore import Qt, QUrl, QVariant
from qgis.PyQt.QtGui import QImage, QResizeEvent, QTextDocument

from oslandia.constants import UTM_CONTENT_ISSUEBROWSER
from oslandia.gitlab_api.upload import UploadRequestManager

# project
from oslandia.gui.auto_resizing_text_browser import AutoResizingTextBrowser
from oslandia.toolbelt.cache_manager import CacheManager
from oslandia.toolbelt.network_manager import NetworkRequestsManager
from oslandia.toolbelt.preferences import PlgOptionsManager


class GitLabTextBrowser(AutoResizingTextBrowser):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_id = None
        self.cache_manager = CacheManager(".oslandia", "cache")

        self.plg_settings = PlgOptionsManager()
        self.loaded_image_resources = []

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

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

    def loadResource(self, resource_type: int, name: QUrl) -> QVariant:
        """Load resource for the QTextDocument

        Download upload image and add it in QTextDocument resources

        :param resourceType: resource type
        :type resourceType: int
        :param name: resource url
        :type name: QUrl
        :return: QVariant for the resource
        :rtype: QVariant
        """
        if not self._project_id:
            return super().loadResource(resource_type, name)

        # For now only load images
        if resource_type == QTextDocument.ResourceType.ImageResource:
            return self._load_image(name)

        return super().loadResource(resource_type, name)

    def _load_image(self, name: QUrl) -> QVariant:
        """Load image in document
        Get from gitlab upload or try to download distant content

        :param name: resource url
        :type name: QUrl
        :return: loaded image, can be null image if resource url can't be access
        :rtype: QVariant
        """

        # Check if url is related to gitlab instance
        plg_settings = PlgOptionsManager.get_plg_settings()

        # If markdown API use, full url of upload is returned
        if plg_settings.use_gitlab_markdown_api:
            base_url = f"{plg_settings.gitlab_url_instance}-/project/{self._project_id}"
        # Otherwise we get directly get the upload secret and name
        else:
            base_url = "/uploads/"
        if name.toString().startswith(base_url):
            if plg_settings.use_gitlab_markdown_api:
                upload_secret_and_name = name.toString().removeprefix(base_url)
            else:
                upload_secret_and_name = name.toString()

            # Download image with manager. Should be replace by cache use
            manager = UploadRequestManager()
            bytea = manager.get_upload(self._project_id, upload_secret_and_name)
        else:
            cache_file = self.cache_manager.get_external_url_cache_path(
                self._project_id, name
            )
            bytea = self.cache_manager.load_cache_file_content(cache_file)
            if not bytea:
                ntwk_requester_blk = NetworkRequestsManager()

                bytea = ntwk_requester_blk.get_url(
                    name,
                    plg_settings.authentification_config_id,
                    caller=UTM_CONTENT_ISSUEBROWSER,
                )
                self.cache_manager.save_cache_file_content(cache_file, bytea)
        # Convert to image
        image = QImage()
        image.loadFromData(bytea)

        # Save to internal list to resize image in document in resizeEvent
        self.loaded_image_resources.append(
            (QTextDocument.ResourceType.ImageResource, name, image)
        )

        # Add to document
        scaled_image = self._scale_image_to_width(image, self.width())
        self.document().addResource(
            QTextDocument.ResourceType.ImageResource, name, scaled_image
        )

        return image

    def _scale_image_to_width(self, image: QImage, width: int) -> QImage:
        """Scale image to width if needed. No scaling is done if image width is lower than wanted width

        :param image: input image
        :type image: QImage
        :param width: width
        :type width: int
        :return: image with scaled width
        :rtype: QImage
        """
        # Scale to width if needed
        if image.width() > width:
            return image.scaledToWidth(
                width, Qt.TransformationMode.SmoothTransformation
            )

        # keep initial image
        return image

    def resizeEvent(self, event: QResizeEvent) -> None:
        """Update QTextDocument images size from widget new size

        :param event: resize event
        :type event: QResizeEvent
        """
        new_size = event.size()
        # Update QTextDocument images size
        for resource_type, name, image in self.loaded_image_resources:
            scaled_image = self._scale_image_to_width(image, new_size.width())
            self.document().addResource(resource_type, name, scaled_image)
        super().resizeEvent(event)
