(function () {
    window.AgentFrontendModules = window.AgentFrontendModules || {};

    window.AgentFrontendModules.createApiBootstrapModule = function createApiBootstrapModule(deps) {
        let authToken = '';
        const frontendClientStorageKey = 'ao_frontend_client_id';

        function createFrontendClientId() {
            if (window.crypto && typeof window.crypto.randomUUID === 'function') {
                return window.crypto.randomUUID();
            }
            return `ao-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
        }

        const frontendClientId = (() => {
            try {
                const existing = sessionStorage.getItem(frontendClientStorageKey);
                if (existing) return existing;
                const created = createFrontendClientId();
                sessionStorage.setItem(frontendClientStorageKey, created);
                return created;
            } catch (_) {
                return createFrontendClientId();
            }
        })();

        function backendOriginCandidates() {
            const candidates = [];
            const seen = new Set();
            const push = (value) => {
                const origin = String(value || '').trim().replace(/\/+$/, '');
                if (!origin) return;
                const key = origin.toLowerCase();
                if (seen.has(key)) return;
                seen.add(key);
                candidates.push(origin);
            };

            if (deps.pageUrl.protocol === 'http:' || deps.pageUrl.protocol === 'https:') {
                push(deps.sameOrigin);
                if (deps.pageUrl.hostname) {
                    push(`${deps.pageUrl.protocol}//${deps.pageUrl.hostname}:8000`);
                    push(`${deps.pageUrl.protocol}//${deps.pageUrl.hostname}:8001`);
                }
            }
            push(deps.defaultBackendOrigin);
            push('http://127.0.0.1:8000');
            push('http://localhost:8000');
            push(deps.launcherOrigin);
            return candidates;
        }

        async function discoverBackendToken() {
            for (const origin of backendOriginCandidates()) {
                try {
                    const response = await fetch(`${origin}/api/auth/token`, {
                        signal: AbortSignal.timeout(2500),
                    });
                    if (!response.ok) continue;
                    const tokenData = await response.json();
                    deps.setBackendUrl(origin);
                    return tokenData.token || '';
                } catch (_) {}
            }
            return '';
        }

        function webSocketHosts() {
            const seen = new Set();
            const candidates = [deps.getPreferredWsHost(), '127.0.0.1', deps.pageUrl.hostname, 'localhost'];
            return candidates.filter((value) => {
                const host = String(value || '').trim();
                if (!host) return false;
                const key = host.toLowerCase();
                if (seen.has(key)) return false;
                seen.add(key);
                return true;
            });
        }

        function buildWebSocketUrl(host) {
            return `${deps.wsProtocol}//${host}:8000/ws`;
        }

        function resolveApiUrl(url) {
            const value = String(url || '');
            if (!value.startsWith('/api/')) return value;
            return `${deps.getBackendUrl()}${value}`;
        }

        async function init() {
            try {
                authToken = await discoverBackendToken();
            } catch (_) {}
        }

        async function refreshAuthToken(options) {
            const preferDiscovery = options && options.preferDiscovery === true;
            if (!preferDiscovery) {
                try {
                    const response = await fetch(resolveApiUrl('/api/auth/token'), {
                        signal: AbortSignal.timeout(3000),
                    });
                    if (response.ok) {
                        const tokenData = await response.json();
                        authToken = tokenData.token || authToken;
                        return true;
                    }
                } catch (_) {}
            }
            try {
                const token = await discoverBackendToken();
                if (token) {
                    authToken = token;
                    return true;
                }
            } catch (_) {}
            return false;
        }

        async function authFetch(url, opts) {
            const requestOptions = opts || {};
            const method = String(requestOptions.method || 'GET').trim().toUpperCase() || 'GET';
            const canRetryServiceUnavailable = method === 'GET' || method === 'HEAD' || method === 'OPTIONS';
            const buildRequestOptions = () => Object.assign({}, requestOptions, {
                headers: Object.assign({}, requestOptions.headers || {}, {
                    Authorization: `Bearer ${authToken}`,
                }),
            });

            if (!authToken && String(url || '').startsWith('/api/')) {
                try {
                    await refreshAuthToken({ preferDiscovery: true });
                } catch (_) {}
            }

            let resolvedUrl = resolveApiUrl(url);
            let response;
            try {
                response = await fetch(resolvedUrl, buildRequestOptions());
            } catch (error) {
                if (!canRetryServiceUnavailable) throw error;
                const recovered = await refreshAuthToken({ preferDiscovery: true });
                if (!recovered) throw error;
                resolvedUrl = resolveApiUrl(url);
                response = await fetch(resolvedUrl, buildRequestOptions());
            }
            if (response.status === 401 || (canRetryServiceUnavailable && (response.status === 502 || response.status === 503 || response.status === 504))) {
                const refreshed = await refreshAuthToken({ preferDiscovery: true });
                if (refreshed || response.status !== 401) {
                    resolvedUrl = resolveApiUrl(url);
                    return fetch(resolvedUrl, buildRequestOptions());
                }
            }
            return response;
        }

        async function authFetchJson(url, opts) {
            const response = await authFetch(url, opts);
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            return response.json();
        }

        function getAuthToken() {
            return authToken;
        }

        return {
            launcherUrl: deps.launcherOrigin,
            frontendClientId,
            webSocketHosts,
            buildWebSocketUrl,
            resolveApiUrl,
            init,
            refreshAuthToken,
            authFetch,
            authFetchJson,
            getAuthToken,
        };
    };
})();