from urllib.parse import quote

from django.shortcuts import redirect
from django.urls import reverse

ALLOWED_PREFIXES = ('/admin/', '/static/', '/media/', '/service-worker.js', '/api/')
ALLOWED_PATH_NAMES = ('accounts:admin_portal', 'accounts:logout')


class AdminRedirectMiddleware:
    """Force any logged-in admin onto the admin portal, on every PAGE
    request. /api/ is allowlisted alongside the static/media assets -- an
    admin-portal page can legitimately fetch() an internal AJAX endpoint
    (region search, weather, etc.) without that call itself being treated
    as a navigation and redirected to a full HTML page, which would break
    every such widget silently (the fetch would resolve with a 200 status
    and an HTML body instead of the expected JSON)."""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        picker_user = request.session.get('picker_user')

        if picker_user and picker_user.get('role') == 'admin':
            allowed_paths = {reverse(name) for name in ALLOWED_PATH_NAMES}
            if request.path not in allowed_paths and not request.path.startswith(ALLOWED_PREFIXES):
                if not request.path.startswith('/accounts/admin-portal/'):
                    return redirect('accounts:admin_portal')

        return self.get_response(request)


POLICY_GATE_EXEMPT_PATH_NAMES = (
    'accounts:logout', 'accounts:accept_policies',
    'market:terms', 'market:privacy', 'market:cookies',
)


class PolicyAcceptanceMiddleware:
    """If a logged-in customer/picker hasn't accepted the current version of
    every legal policy (either they never accepted, or admin edited a policy
    since they last did), send them to the accept-policies interstitial
    before anything else. Only intercepts real page navigations (browser
    'Accept: text/html' requests) — not JS polling/fetch calls, which would
    otherwise silently break mid-page if redirected to an HTML page."""

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        picker_user = request.session.get('picker_user')

        if (
            picker_user
            and picker_user.get('role') in ('customer', 'picker')
            and request.method == 'GET'
            and 'text/html' in request.headers.get('Accept', '')
            and not request.path.startswith(ALLOWED_PREFIXES)
        ):
            exempt_paths = {reverse(name) for name in POLICY_GATE_EXEMPT_PATH_NAMES}
            if request.path not in exempt_paths:
                from market.legal_policies import get_outdated_policies

                if get_outdated_policies(picker_user['id']):
                    return redirect(f"{reverse('accounts:accept_policies')}?next={quote(request.get_full_path())}")

        return self.get_response(request)
