import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
vi.mock("node:os", async () => {
    const actual = await vi.importActual("node:os");
    const mocked = {
        ...actual,
        homedir: () => process.env.AWS_TEST_HOME || actual.homedir(),
    };
    return {
        ...mocked,
        default: mocked,
    };
});
vi.mock("axios", () => ({
    default: {
        post: vi.fn(),
    },
}));
const originalEnv = { ...process.env };
const tempRoots = [];
function createRuntimeHome() {
    const root = mkdtempSync(path.join(os.tmpdir(), "aws-auto-register-"));
    tempRoots.push(root);
    return root;
}
function writeAutoRegisterConfig(homeDir, targets) {
    const configPath = path.join(homeDir, ".aws-bridge", "config.json");
    const autoRegisterTargets = (typeof targets === "string"
        ? [{ serverUrl: targets }]
        : targets).map((target, index) => ({
        serverUrl: target.serverUrl,
        instanceName: target.instanceName || `test-bridge-${index + 1}`,
        userKey: target.userKey || `aws_live_test_key_${index + 1}`,
        registerIp: target.registerIp || "127.0.0.1",
    }));
    mkdirSync(path.dirname(configPath), { recursive: true });
    writeFileSync(configPath, `${JSON.stringify({
        connectionKey: "bridge-key",
        autoRegisterTargets,
    }, null, 2)}\n`, "utf-8");
}
function useRuntimeHome(runtimeHome) {
    process.env.AWS_TEST_HOME = runtimeHome;
    process.env.HOME = runtimeHome;
    process.env.USERPROFILE = runtimeHome;
    process.env.AWS_RUNTIME_HOME_DIR = runtimeHome;
    process.env.AWS_RUNTIME_SCHEDULER_BASE_URL = "";
}
async function mockSuccessfulPost(response) {
    const { default: axios } = await import("axios");
    vi.mocked(axios.post).mockResolvedValue({ data: response });
    return vi.mocked(axios.post);
}
afterEach(() => {
    process.env = { ...originalEnv };
    vi.resetModules();
    vi.clearAllMocks();
    vi.restoreAllMocks();
    for (const root of tempRoots.splice(0)) {
        rmSync(root, { recursive: true, force: true });
    }
});
describe("auto-register scheduler URL selection", () => {
    it("uses configured serverUrl for lifecycle callbacks when env scheduler URL is absent", async () => {
        const runtimeHome = createRuntimeHome();
        useRuntimeHome(runtimeHome);
        writeAutoRegisterConfig(runtimeHome, "http://127.0.0.1:7380");
        const post = await mockSuccessfulPost({
            success: true,
            instanceId: "bridge-instance-1",
            userId: "user-1",
            message: "ok",
            runtimeAccessToken: "runtime-token-123456",
        });
        const { autoRegister, bridgeRestartCleanup, requestRuntimeAccessTokenRefresh, unregister } = await import("./auto-register.js");
        await expect(autoRegister()).resolves.toBe(true);
        await expect(bridgeRestartCleanup()).resolves.toMatchObject({ success: true });
        post.mockResolvedValueOnce({
            data: {
                success: true,
                runtimeAccessToken: "refreshed-token-123456",
                userId: "user-1",
            },
        });
        await expect(requestRuntimeAccessTokenRefresh()).resolves.toMatchObject({
            success: true,
            runtimeAccessToken: "refreshed-token-123456",
        });
        post.mockResolvedValueOnce({ data: { success: true, message: "unregistered" } });
        await expect(unregister()).resolves.toBe(true);
        expect(post.mock.calls[0]?.[0]).toBe("http://127.0.0.1:7380/api/instances/register");
        expect(post.mock.calls[1]?.[0]).toBe("http://127.0.0.1:7380/api/instances/bridge-restart-cleanup");
        expect(post.mock.calls[2]?.[0]).toBe("http://127.0.0.1:7380/api/instances/runtime-tokens/refresh");
        expect(post.mock.calls[3]?.[0]).toBe("http://127.0.0.1:7380/api/instances/unregister");
        expect(post.mock.calls[3]?.[2]?.headers?.["X-Runtime-Token"]).toBe("refreshed-token-123456");
        const { getRuntimeAccessToken, loadRuntimeBinding } = await import("./runtime-binding.js");
        expect(getRuntimeAccessToken("user-1", "http://127.0.0.1:7380")).toBeUndefined();
        expect(loadRuntimeBinding().status).toBe("unpaired");
    });
    it("uses the registered target URL instead of the first configured target", async () => {
        const runtimeHome = createRuntimeHome();
        useRuntimeHome(runtimeHome);
        writeAutoRegisterConfig(runtimeHome, [
            { serverUrl: "http://scheduler-a.local:7380", userKey: "aws_live_key_a" },
            { serverUrl: "http://scheduler-b.local:7380", userKey: "aws_live_key_b" },
        ]);
        const post = await mockSuccessfulPost({ success: false, message: "unexpected" });
        post.mockResolvedValueOnce({
            data: {
                success: true,
                instanceId: "bridge-a",
                userId: "user-a",
                runtimeAccessToken: "runtime-token-a-123456",
            },
        });
        post.mockResolvedValueOnce({
            data: {
                success: true,
                instanceId: "bridge-b",
                userId: "user-b",
                runtimeAccessToken: "runtime-token-b-123456",
            },
        });
        post.mockResolvedValueOnce({ data: { success: true, message: "cleanup ok" } });
        const { autoRegister, bridgeRestartCleanup } = await import("./auto-register.js");
        await expect(autoRegister()).resolves.toBe(true);
        await expect(bridgeRestartCleanup()).resolves.toMatchObject({ success: true });
        expect(post.mock.calls[0]?.[0]).toBe("http://scheduler-a.local:7380/api/instances/register");
        expect(post.mock.calls[1]?.[0]).toBe("http://scheduler-b.local:7380/api/instances/register");
        expect(post.mock.calls[2]?.[0]).toBe("http://scheduler-b.local:7380/api/instances/bridge-restart-cleanup");
    });
    it("falls back to paired runtime binding scheduler URL when config has no serverUrl", async () => {
        const runtimeHome = createRuntimeHome();
        useRuntimeHome(runtimeHome);
        const post = await mockSuccessfulPost({
            success: true,
            runtimeAccessToken: "binding-refresh-token-123456",
            userId: "user-from-binding",
        });
        const { saveRuntimeBinding } = await import("./runtime-binding.js");
        const { requestRuntimeAccessTokenRefresh } = await import("./auto-register.js");
        saveRuntimeBinding({
            accessToken: "existing-binding-token-123456",
            instanceId: "bridge-from-binding",
            userId: "user-from-binding",
            schedulerBaseUrl: "http://paired-scheduler.local:7380",
        });
        process.env.AWS_AUTO_REGISTER = "true";
        process.env.AWS_USER_KEY = "aws_live_env_key";
        await expect(requestRuntimeAccessTokenRefresh()).resolves.toMatchObject({
            success: true,
            runtimeAccessToken: "binding-refresh-token-123456",
        });
        expect(post.mock.calls[0]?.[0]).toBe("http://paired-scheduler.local:7380/api/instances/runtime-tokens/refresh");
    });
});
