import { describe, test, expect, beforeEach, afterEach } from "bun:test";
import { mockClient } from "aws-sdk-client-mock";
import { CodeartifactClient, GetAuthorizationTokenCommand } from "@aws-sdk/client-codeartifact";
import { configureCodeArtifactAuth } from "@/utils/codeartifact.js";
import type { CodeArtifactConfig } from "@/utils/codeartifact.js";
import { createLogger } from "@/utils/logger.js";
import type { Logger } from "pino";

const caMock = mockClient(CodeartifactClient);

const TEST_CFG: CodeArtifactConfig = {
  domain: "test-domain",
  domainOwner: "123456789012",
  region: "us-east-1",
};

describe("configureCodeArtifactAuth", () => {
  let logger: Logger;
  let savedToken: string | undefined;
  let disposer: (() => void) | undefined;

  beforeEach(() => {
    caMock.reset();
    logger = createLogger("silent");
    savedToken = process.env.CODEARTIFACT_AUTH_TOKEN;
    delete process.env.CODEARTIFACT_AUTH_TOKEN;
    disposer = undefined;
  });

  afterEach(() => {
    // Always stop the refresh interval so setInterval handles don't leak
    // between tests — even if a happy-path test forgets to call disposer.
    disposer?.();
    if (savedToken === undefined) {
      delete process.env.CODEARTIFACT_AUTH_TOKEN;
    } else {
      process.env.CODEARTIFACT_AUTH_TOKEN = savedToken;
    }
  });

  test("successful token fetch sets env var and returns disposer", async () => {
    caMock.on(GetAuthorizationTokenCommand).resolves({
      authorizationToken: "fake-token-abc",
    });

    disposer = await configureCodeArtifactAuth(TEST_CFG, logger);

    expect(process.env.CODEARTIFACT_AUTH_TOKEN).toBe("fake-token-abc");
    expect(typeof disposer).toBe("function");
    // afterEach calls disposer()
  });

  test("SDK failure rejects the promise", async () => {
    caMock.on(GetAuthorizationTokenCommand).rejects(new Error("AWS SDK error"));

    await expect(configureCodeArtifactAuth(TEST_CFG, logger)).rejects.toThrow("AWS SDK error");
  });

  test("empty authorization token from AWS throws", async () => {
    caMock.on(GetAuthorizationTokenCommand).resolves({
      authorizationToken: undefined,
    });

    await expect(configureCodeArtifactAuth(TEST_CFG, logger)).rejects.toThrow(
      "CodeArtifact returned empty authorization token",
    );
  });

  test("disposer is idempotent — calling twice does not throw", async () => {
    caMock.on(GetAuthorizationTokenCommand).resolves({
      authorizationToken: "token-123",
    });

    disposer = await configureCodeArtifactAuth(TEST_CFG, logger);
    disposer();
    expect(() => disposer?.()).not.toThrow();
  });
});
