"""Parse a page and add a Link header to the request, which CloudFlare can use to push static media to an HTTP/2 client."""

from django.conf import settings
from django.contrib.staticfiles import storage
from django.contrib.staticfiles.templatetags import staticfiles
from django.core.files.storage import get_storage_class
from django.utils.functional import LazyObject


EXTENSION_AS = {
    'js': 'script',
    'css': 'style',
    'png': 'image',
    'jpg': 'image',
    'jpeg': 'image',
    'svg': 'image',
    'gif': 'image',
    'ttf': 'font',
    'woff': 'font',
    'woff2': 'font'
}
FILE_FILTER = getattr(settings, 'CLOUDFLARE_PUSH_FILTER', lambda x: True)


class FileCollector(object):
    def __init__(self):
        self.collection = []

    def collect(self, path):
        if not path.endswith('/') and FILE_FILTER(path.lower()):
            self.collection.append(path)


def storage_factory(collector):
    class DebugConfiguredStorage(LazyObject):
        def _setup(self):
            configured_storage_cls = get_storage_class(settings.STATICFILES_STORAGE)

            class DebugStaticFilesStorage(configured_storage_cls):

                def __init__(self, collector, *args, **kwargs):
                    super(DebugStaticFilesStorage, self).__init__(*args, **kwargs)
                    self.collector = collector

                def url(self, path):
                    self.collector.collect(path)
                    return super(DebugStaticFilesStorage, self).url(path)

            self._wrapped = DebugStaticFilesStorage(collector)
    return DebugConfiguredStorage


def sort_urls(urls):
    """
    Order URLs by extension.
    This function accepts a list of URLs and orders them by their extension.
    CSS files are sorted to the start of the list, then JS, then everything
    else.
    """
    order = {"css": 0, "js": 1}
    urls.sort(key=lambda x: order.get(x.rsplit(".")[-1].lower(), 2))
    return urls


def create_header_content(urls):
    """
    Creates the content for the Link header.
    """
    links = []
    for url in urls[:10]:
        ext = url.rsplit(".")[-1].lower()
        if ext in EXTENSION_AS:
            link = "<%s>; rel=preload; as=%s" % (url, EXTENSION_AS[ext])
        else:
            link = "<%s>; rel=preload" % (url,)
        links.append(link)
    return ", ".join(links)


def push_middleware(get_response):
    def middleware(request):
        collector = FileCollector()
        storage.staticfiles_storage = staticfiles.staticfiles_storage = storage_factory(collector)()
        response = get_response(request)
        collection_copy = list(collector.collection)  # For compatibility with 2.7.
        urls = list(set(storage.staticfiles_storage.url(f) for f in collection_copy))
        urls = sort_urls(urls)
        response["Link"] = create_header_content(urls)
        return response
    return middleware