import os
import posixpath

from pathlib import Path

from django.utils._os import safe_join
from django.utils.http import http_date
from django.utils.translation import gettext as _
from django.contrib.staticfiles import finders
from django.conf import settings
from django.views.static import directory_index, was_modified_since
from django.http import (
    FileResponse, Http404, HttpResponseNotModified, StreamingHttpResponse
)

from .sourcefile import SourceFile
from .conf import settings as deno_settings
from .api.rollup import DenoRollup


# from django.views.static import serve
def serve_rollup(request, path, document_root=None, show_indexes=False):
    """
    Serve static files below a given point in the directory structure.

    To use, put a URL pattern such as::

        from django.views.static import serve

        path('<path:path>', serve, {'document_root': '/path/to/my/files/'})

    in your URLconf. You must provide the ``document_root`` param. You may
    also set ``show_indexes`` to ``True`` if you'd like to serve a basic index
    of the directory.  This index view will use the template hardcoded below,
    but if you'd like to override it, you can create a template called
    ``static/directory_index.html``.
    """
    path = posixpath.normpath(path).lstrip('/')
    fullpath = Path(safe_join(document_root, path))
    if fullpath.is_dir():
        if show_indexes:
            return directory_index(path, fullpath)
        raise Http404(_("Directory indexes are not allowed here."))
    if not fullpath.exists():
        raise Http404(_('“%(path)s” does not exist') % {'path': fullpath})
    statobj = fullpath.stat()

    source_file = SourceFile(fullpath)
    if source_file.should_rollup():
        response = DenoRollup(content_type=source_file.content_type).post({
            'filename': str(fullpath.name),
            'basedir': str(fullpath.parent),
            'options': deno_settings.DENO_ROLLUP_SERVE_OPTIONS,
        })
        if not isinstance(response, StreamingHttpResponse):
            # report error
            return response
    else:
        # Respect the If-Modified-Since header.
        if not was_modified_since(request.META.get('HTTP_IF_MODIFIED_SINCE'),
                                  statobj.st_mtime, statobj.st_size):
            return HttpResponseNotModified()
        response = FileResponse(fullpath.open('rb'), content_type=source_file.content_type)
    response["Last-Modified"] = http_date(statobj.st_mtime)
    if source_file.encoding:
        response["Content-Encoding"] = source_file.encoding
    return response


# from django.contrib.staticfiles.views import serve
def serve(request, path, insecure=False, **kwargs):
    """
    Serve static files below a given point in the directory structure or
    from locations inferred from the staticfiles finders.

    To use, put a URL pattern such as::

        from django.contrib.staticfiles import views

        path('<path:path>', views.serve)

    in your URLconf.

    It uses the django.views.static.serve() view to serve the found files.
    """
    if not settings.DEBUG and not insecure:
        raise Http404
    normalized_path = posixpath.normpath(path).lstrip('/')
    absolute_path = finders.find(normalized_path)
    if not absolute_path:
        if path.endswith('/') or path == '':
            raise Http404("Directory indexes are not allowed here.")
        raise Http404("'%s' could not be found" % path)
    document_root, path = os.path.split(absolute_path)
    return serve_rollup(request, path, document_root=document_root, **kwargs)
