import os

from django import template
from django.conf import settings
from django.contrib.staticfiles import finders
from django.templatetags.static import static as _static

register = template.Library()

# Populated once per process in production (files only change on a deploy,
# which restarts the process); re-stat'd on every call in DEBUG so local
# edits show up immediately without a server restart.
_version_cache = {}


def _mtime(path):
    try:
        return int(os.path.getmtime(path))
    except OSError:
        return None


def _get_version(path):
    if not settings.DEBUG and path in _version_cache:
        return _version_cache[path]

    # Dev: read straight from the source static/ dirs, so an edit to a JS/CSS
    # file busts the cache on the very next request — no collectstatic needed.
    version = None
    found = finders.find(path)
    if found:
        version = _mtime(found)

    # Production: static/ isn't served from source, only from the collected
    # STATIC_ROOT copy (built by collectstatic as part of the deploy), so
    # fall back to that file's mtime instead.
    if version is None and settings.STATIC_ROOT:
        version = _mtime(os.path.join(settings.STATIC_ROOT, path))

    if not settings.DEBUG:
        _version_cache[path] = version
    return version


@register.simple_tag
def static_v(path):
    """Same as {% static %}, but appends ?v=<mtime> for local files so a
    browser that already cached the old URL reliably fetches the new one
    after a deploy (or, in dev, after any edit) instead of serving a stale
    copy indefinitely — static files are otherwise sent with no Cache-Control
    header at all, so browsers fall back to long heuristic caching."""
    url = _static(path)
    version = _get_version(path)
    if version is None:
        return url
    separator = '&' if '?' in url else '?'
    return f'{url}{separator}v={version}'
