from .interfaces import IPreviewSettings
from BTrees.OOBTree import OOBTree
from DateTime import DateTime
from logging import getLogger
from OFS.interfaces import IItem
from plone.dexterity.interfaces import IDexterityContent
from plone.namedfile.interfaces import INamedField
from plone.protect.interfaces import IDisableCSRFProtection
from plone.protect.utils import safeWrite
from plone.rfc822.interfaces import IPrimaryFieldInfo
from ploneintranet.docconv.client.interfaces import IFileWrapper
from ploneintranet.docconv.client.utils import PDF_FILENAME
from zope.annotation.interfaces import IAnnotations
from zope.cachedescriptors.property import Lazy as lazy_property
from zope.component import adapter
from zope.globalrequest import getRequest
from zope.interface import alsoProvides
from zope.interface import implementer

import os

log = getLogger(__name__)


@implementer(IFileWrapper)
@adapter(IItem)
class BaseItem:
    def __init__(self, context):
        self.context = context

    @property
    def has_enclosure(self):
        """This was checking for IFileContent.providedBy(self.context)
        but IFileContent is AT only
        """
        return False

    @lazy_property
    def _field(self):
        return self.context.getField("file") or self.context.getPrimaryField()

    @lazy_property
    def file(self):
        if self.has_enclosure:
            wrapper = self._field.get(self.context)
            return wrapper

    @property
    def file_length(self):
        return self.file.get_size()

    @property
    def file_type(self):
        return self.context.getContentType()

    @property
    def blob(self):
        return self.file.getBlob()

    @property
    def filename(self):
        return os.path.basename(self._field.getFilename(self.context))


@adapter(IDexterityContent)
class DexterityItem(BaseItem):
    def __init__(self, context):
        super().__init__(context)
        try:
            self.primary = IPrimaryFieldInfo(self.context, None)
        except TypeError:
            # plone/dexterity/primary.py raises TypeError("Could not adapt")
            # if there is not primary field
            self.primary = None

    @property
    def has_enclosure(self):
        if self.primary:
            return INamedField.providedBy(self.primary.field)
        else:
            return False

    @lazy_property
    def file(self):
        if self.has_enclosure:
            return self.primary.field.get(self.context)

    @property
    def file_length(self):
        if self.file:
            return self.file.getSize()

    @property
    def file_type(self):
        if self.file:
            return self.file.contentType

    @property
    def blob(self):
        if self.file:
            return self.file._blob

    @property
    def filename(self):
        if self.file:
            return self.file.filename
        elif self.primary is not None and self.primary.field.__name__ == "text":
            return self.context.getId() + ".html"

        return "dump.bin"


@implementer(IPreviewSettings)
@adapter(IDexterityContent)
class Settings:
    def __init__(self, context):
        self.context = context
        annotations = IAnnotations(self.context)

        self._metadata = annotations.get("ploneintranet.docconv.client", None)
        if self._metadata is None:
            self._metadata = OOBTree()
            self._metadata["last_updated"] = DateTime("1901/01/01").ISO8601()
            annotations["ploneintranet.docconv.client"] = self._metadata
            safeWrite(self.context)

        self._migrate_old_data()

    def _migrate_old_data(self):
        """Compatibility support of old c.dv datastructure
        A minimal valid set for conversion is either a pdf/dump.pdf
        or at least the large/dump_1.gif file.
        if one of these are given, we take them and copy the metadata
        if not, we discard the oldmetadata
        """
        annotations = IAnnotations(self.context)
        oldmetadata = annotations.get("collective.documentviewer", None)

        if oldmetadata is None:
            return

        def copy_meta(old, new):
            supported_attributes = (
                "last_updated",
                "num_pages",
                "successfully_converted",
                "converting",
            )
            for attr in supported_attributes:
                if attr in old:
                    new[attr] = old[attr]

        request = getRequest()
        if request:
            alsoProvides(getRequest(), IDisableCSRFProtection)
        log.info("Attempting to migrate old style preview data to new svg support.")
        new_blobs = self._metadata.get("blob_files", OOBTree())

        # Convert to new datastructure and clean up
        if "blob_files" in oldmetadata:
            pdf_path = f"pdf/{PDF_FILENAME}"
            if pdf_path in oldmetadata["blob_files"]:
                # If we find an old pdf, we use it and are done.
                new_blobs[PDF_FILENAME] = oldmetadata["blob_files"][pdf_path]
                copy_meta(oldmetadata, self._metadata)
                self.blob_files = new_blobs
                log.info("Found pdf version. Reusing and supporting svg…")
            elif "large/dump_1.gif" in oldmetadata["blob_files"]:
                # If there was no old pdf, but we have previews, we use
                # them and are done
                for item in oldmetadata["blob_files"]:
                    if item.startswith("large/dump_"):
                        filename = item.replace("large/", "")
                        new_blobs[filename] = oldmetadata["blob_files"][item]
                copy_meta(oldmetadata, self._metadata)
                self.blob_files = new_blobs
                log.info("Found gif previews. Reusing but not using svg…")
            else:
                log.info(
                    "Old c.dv datastructure found but it contained no "
                    "reusable data. Discarding…"
                )

        # Now we cleanup. If there was something to reuse, we have.
        # The rest is no longer needed.
        log.info("Cleaning up old c.dv datastructure.")
        annotations.pop("collective.documentviewer")

    def __setattr__(self, name, value):
        if name[0] == "_" or name in ["context"]:
            self.__dict__[name] = value
        else:
            self._metadata[name] = value

    def __getattr__(self, name):
        value = self._metadata.get(name, None)

        return value
