from .interfaces import IAppContainer
from .interfaces import IAppContent
from logging import getLogger
from plone import api
from plone.app.contenttypes.interfaces import ILink
from plone.app.uuid.utils import uuidToPhysicalPath
from plone.dexterity.filerepresentation import DefaultReadFile
from plone.memoize import ram
from Products.CMFCore.interfaces import ISiteRoot
from time import time
from urllib.parse import urlparse
from zope.component import adapter
from zope.interface import implementer

import requests

logger = getLogger(__name__)


def _link_cache_key(func, self):
    """This is expected to be used for adapters/views that have a Link context

    The cache depends only on the remoteUrl
    """
    return (func.__name__, self.context.remoteUrl, time() // 300)


@implementer(IAppContent)
class AppContent:
    def __init__(self, context):
        self.context = context

    @property
    def app_name(self):
        return getattr(self.get_app(), "app_name", "")

    @property
    def in_app(self):
        return bool(self.get_app())

    def get_app(self):
        if IAppContainer.providedBy(self.context):
            return self.context
        else:
            for item in self.context.aq_chain:
                if IAppContainer.providedBy(item):
                    return item
                elif ISiteRoot.providedBy(item):
                    return None
        return None


@adapter(ILink)
class LinkReadFile(DefaultReadFile):
    """This is needed to override the adapt the content_type method of link files"""

    _known_youtube_urls = [
        "m.youtube.com",
        "www.youtube-nocookie.com",
        "www.youtube.com",
        "youtu.be",
        "youtube.com",
    ]

    def _is_youtube(self):
        """Let's try to sniff if this is a link to a youtube video"""
        return urlparse(self.context.remoteUrl).netloc in self._known_youtube_urls

    def _is_video(self):
        """Let's try to sniff if this is a link to a video, we make an HEAD
        request to get the content type
        """
        if not self.context.remoteUrl:
            return False

        if self.context.remoteUrl.startswith(
            "${portal_url}"
        ) or self.context.remoteUrl.startswith("${navigatrion_root_url}"):
            path = self.context.remoteUrl.partition("/")[-1]
            if path.startswith("resolveuid/"):
                uid = path.partition("resolveuid/")[-1]
                path = uuidToPhysicalPath(uid)
            obj = api.portal.get().unrestrictedTraverse(path, None)
            if obj:
                try:
                    return obj.content_type().startswith("video/")
                except Exception:
                    # Something that does not have a content_type is not a video
                    return False
            return False

        response = None
        try:
            response = requests.head(self.context.remoteUrl, timeout=5)
        except requests.exceptions.ConnectTimeout:
            logger.info(
                "Timeout when checking if %r is a video", self.context.remoteUrl
            )
        except BaseException:
            logger.info("Failed to check if %r is a video", self.context.remoteUrl)
        if response is None:
            return False
        return response.headers.get("Content-Type", "").partition("/")[0] == "video"

    @property
    @ram.cache(_link_cache_key)
    def mimeType(self):
        """Return a custom media type for out link, based on where it points"""
        if not self.context.remoteUrl:
            return "text/x-uri"
        if self._is_youtube():
            return "text/x-uri-youtube"
        if self._is_video():
            return "text/x-uri-video"
        return "text/x-uri"
