import { findContextByMemoryUrl, getActiveOrg, getMemoryUrl, getToken, resolveContext, setActiveOrg as setContextActiveOrg, setMemoryUrl as setContextMemoryUrl, } from "../../../internal/index.js";
export function normalizeMcpUrl(input) {
    const url = new URL(input);
    url.hash = "";
    url.search = "";
    if (!url.pathname || url.pathname === "/") {
        url.pathname = "/mcp";
    }
    else if (!url.pathname.startsWith("/mcp")) {
        url.pathname = `${url.pathname.replace(/\/+$/, "")}/mcp`;
    }
    return url.toString().replace(/\/+$/, "");
}
/** Strip org suffix from an MCP URL for server-level defaults: /mcp/acme → /mcp */
export function baseMcpUrl(input) {
    const url = new URL(normalizeMcpUrl(input));
    url.hash = "";
    url.search = "";
    url.pathname = "/mcp";
    return url.toString().replace(/\/+$/, "");
}
/** Build an org-scoped MCP URL: `https://host/mcp/{org}` */
export function mcpUrlForOrg(baseUrl, org) {
    const url = new URL(normalizeMcpUrl(baseUrl));
    url.pathname = `/mcp/${org}`;
    return url.toString().replace(/\/+$/, "");
}
/** Extract org slug from a /mcp/{org} URL, or null if bare /mcp */
export function orgFromMcpUrl(mcpUrl) {
    try {
        const { pathname } = new URL(mcpUrl);
        const match = pathname.match(/^\/mcp\/([^/]+)/);
        return match?.[1] ?? null;
    }
    catch {
        return null;
    }
}
export async function setActiveOrg(orgSlug, context) {
    await setContextActiveOrg(orgSlug, context);
}
export async function setActiveMcpUrl(mcpUrl, context) {
    await setContextMemoryUrl(mcpUrl, context);
}
export async function getActiveSession(context) {
    const base = await resolveServerUrl(undefined, context);
    const org = await resolveOrg(undefined, undefined, context);
    const key = org ? mcpUrlForOrg(base, org) : base;
    return {
        session: {
            mcpUrl: key,
            org,
            tokenType: "Bearer",
            updatedAt: new Date().toISOString(),
        },
        key,
    };
}
export async function getSessionForOrg(orgSlug, context, urlFlag) {
    const base = await resolveServerUrl(urlFlag, context);
    const key = mcpUrlForOrg(base, orgSlug);
    return {
        session: {
            mcpUrl: key,
            org: orgSlug,
            tokenType: "Bearer",
            updatedAt: new Date().toISOString(),
        },
        key,
    };
}
/**
 * Resolve which server URL to use.
 * Priority: explicit url arg > LOBU_MEMORY_URL > context preference > cloud default.
 */
export async function resolveServerUrl(urlFlag, context) {
    if (urlFlag)
        return normalizeMcpUrl(urlFlag);
    return normalizeMcpUrl(await getMemoryUrl(context));
}
/**
 * Resolve which org to use.
 * Priority: explicit org arg > LOBU_MEMORY_ORG > session > context preference.
 */
export async function resolveOrg(orgFlag, session, context) {
    if (orgFlag)
        return orgFlag;
    if (process.env.LOBU_MEMORY_ORG)
        return process.env.LOBU_MEMORY_ORG;
    if (session?.org)
        return session.org;
    return getActiveOrg(context);
}
/**
 * Resolve a usable bearer token from top-level `lobu login` credentials.
 */
export async function getUsableToken(mcpUrl, contextName) {
    let target = await resolveContext(contextName);
    const resolvedUrl = mcpUrl
        ? normalizeMcpUrl(mcpUrl)
        : await resolveServerUrl(undefined, target.name);
    if (mcpUrl && !contextName) {
        const requestedBase = baseMcpUrl(resolvedUrl);
        const currentContextUrl = await resolveServerUrl(undefined, target.name);
        const currentContextBase = baseMcpUrl(currentContextUrl);
        // Keep the active context when it already targets the requested memory
        // server. Multiple contexts can legitimately share the default memory URL,
        // and blindly picking the first matching context can select credentials for
        // an unrelated context (or one with no login), causing unauthenticated MCP
        // requests.
        if (currentContextBase !== requestedBase) {
            const matched = await findContextByMemoryUrl(resolvedUrl);
            if (matched)
                target = matched;
        }
    }
    if (mcpUrl && !process.env.LOBU_API_TOKEN) {
        const contextUrl = await resolveServerUrl(undefined, target.name);
        const requestedBase = baseMcpUrl(resolvedUrl);
        const contextBase = baseMcpUrl(contextUrl);
        if (requestedBase !== contextBase) {
            throw new Error(`Refusing to send stored context credentials for "${target.name}" to ${requestedBase}. Configure that context's memory URL or set LOBU_API_TOKEN explicitly.`);
        }
    }
    const token = await getToken(target.name);
    if (!token)
        return null;
    const org = orgFromMcpUrl(resolvedUrl) ??
        (await resolveOrg(undefined, undefined, target.name));
    const sessionUrl = org && !orgFromMcpUrl(resolvedUrl)
        ? mcpUrlForOrg(resolvedUrl, org)
        : resolvedUrl;
    return {
        token,
        contextName: target.name,
        session: {
            mcpUrl: sessionUrl,
            org,
            tokenType: "Bearer",
            updatedAt: new Date().toISOString(),
        },
    };
}
//# sourceMappingURL=openclaw-auth.js.map