/*
 * Provider-portal AJAX URL handling (MP-697).
 *
 * When `provider_auto_redirect` is on, Service Provider users browse under the
 * /provider/* namespace and backend\components\ProviderAwareUrlManager prefixes
 * every PHP-generated URL accordingly. But URLs hardcoded in JavaScript
 * (task-manager.js '/task/list', ha-rule-manager.js '/ha-affinity-rule/*',
 * inline view $.ajax calls, ...) never pass through the PHP URL manager, so
 * they hit the unprefixed route. backend\components\PortalModeFilter answers
 * such AJAX requests with a 403 naming the canonical /provider URL.
 *
 * Two layers keep that working without the user ever seeing a 403:
 *
 *   1. PREFILTER (primary) — while the page itself is under /provider, rewrite
 *      outgoing same-origin app URLs to their /provider equivalent *before*
 *      they are sent. The request goes to the right place the first time, so
 *      no 403 is produced and no retry round-trip is needed. Routes the server
 *      never redirects (API, auth, admin, ...) are left untouched, using the
 *      exempt list the server hands us in window.MP_PROVIDER.
 *
 *   2. SAFETY NET (fallback) — if a 403 contract response slips through anyway
 *      (e.g. an AJAX call fired from a non-/provider page), re-issue it against
 *      the URL named in the response body. This should rarely fire once the
 *      prefilter is in place.
 *
 * When the setting is off, SP users are not under /provider, the prefilter is
 * inert, and the server never emits the contract — so this file is a no-op.
 */
(function () {
    'use strict';

    if (typeof window.jQuery === 'undefined') {
        return;
    }

    var $ = window.jQuery;
    var PROVIDER_PREFIX_ERROR = 'service_provider_routes_require_provider_prefix';

    // The layout hands us the canonical prefix and the server's exempt-route
    // list. Without it we cannot know which routes must NOT be prefixed, so the
    // prefilter stays disabled and we rely on the 403 safety net alone rather
    // than risk prefixing an exempt route (API/auth/admin) and breaking it.
    var config = window.MP_PROVIDER;
    var PREFIX = (config && config.prefix) || '/provider';
    var EXEMPT = (config && config.exempt) || [];
    var prefilterEnabled = !!config;

    // True when the current page is itself served under the provider namespace.
    // That is the signal that this user's session is in provider mode, so app
    // AJAX from this page should target /provider/<route> too.
    function onProviderPage() {
        var path = window.location.pathname;
        return path === PREFIX || path.indexOf(PREFIX + '/') === 0;
    }

    // Mirror of PortalModeFilter's fnmatch check for the simple patterns the
    // exempt list uses: an exact route, or a 'segment/*' prefix wildcard.
    function isExemptRoute(route) {
        for (var i = 0; i < EXEMPT.length; i++) {
            var pattern = EXEMPT[i];
            if (pattern.slice(-2) === '/*') {
                var base = pattern.slice(0, -2);
                if (route === base || route.indexOf(base + '/') === 0) {
                    return true;
                }
            } else if (pattern === route) {
                return true;
            }
        }
        return false;
    }

    // ---- Layer 1: prefilter outgoing requests on provider pages -------------
    $.ajaxPrefilter(function (options) {
        if (!prefilterEnabled || !onProviderPage()) {
            return;
        }

        var url = options.url;
        // Only rewrite root-relative same-origin URLs ("/task/list"). Skip
        // absolute ("http://"), protocol-relative ("//host") and relative URLs.
        if (typeof url !== 'string' || url.charAt(0) !== '/' || url.charAt(1) === '/') {
            return;
        }
        // Already under /provider — nothing to do.
        if (url === PREFIX || url.indexOf(PREFIX + '/') === 0) {
            return;
        }

        // Derive the Yii route (path without leading slash, query or fragment)
        // to test against the exempt list, which is expressed in route form.
        var path = url.split('#')[0].split('?')[0];
        var route = path.replace(/^\/+/, '');
        if (isExemptRoute(route)) {
            return;
        }

        options.url = PREFIX + url;
    });

    // ---- Layer 2: honour the 403 contract for anything that slips through ---
    $(document).ajaxError(function (event, jqXHR, settings) {
        if (!jqXHR || jqXHR.status !== 403) {
            return;
        }

        // jQuery only reliably populates jqXHR.responseJSON for 2xx responses;
        // on an error status (our 403) it is usually undefined even when the
        // body is JSON. Fall back to parsing responseText so the contract is
        // honoured regardless of jQuery version or the caller's dataType.
        var body = jqXHR.responseJSON;
        if (!body) {
            try {
                body = JSON.parse(jqXHR.responseText || 'null');
            } catch (e) {
                return;
            }
        }
        if (!body || body.error !== PROVIDER_PREFIX_ERROR || !body.redirect) {
            return;
        }

        // Guard against re-entry. The redirect target lives under /provider/*,
        // which PortalModeFilter never re-redirects, so a second 403 should be
        // impossible — but the sentinel keeps a misconfiguration from looping.
        if (settings && settings._providerPrefixRetried) {
            return;
        }

        var retry = $.extend({}, settings, {
            url: body.redirect,
            _providerPrefixRetried: true
        });

        $.ajax(retry);
    });
})();
