import assert from "node:assert/strict";
import { readFile, unlink } from "node:fs/promises";
import { tmpdir } from "node:os";
import test from "node:test";
import { archiveKey, SalesforceClient } from "./salesforce.js";
import type { ArchiveSource, SalesforceAccessToken, TokenProvider } from "./types.js";

const tokens: TokenProvider<SalesforceAccessToken> = {
  async getToken(): Promise<SalesforceAccessToken> {
    return {
      accessToken: "salesforce-token",
      instanceUrl: "https://example.my.salesforce.com",
      expiresAt: Date.now() + 60_000,
    };
  },
};

const discoveryOptions = {
  apiVersion: "63.0",
  allowedObjects: ["Account"],
  contentVersionRetentionMonths: 7,
  attachmentRetentionMonths: 6,
};

test("archive key is deterministic per source and destination parent", () => {
  assert.equal(
    archiveKey("ContentVersion", "068000000000001", "001000000000001"),
    archiveKey("ContentVersion", "068000000000001", "001000000000001"),
  );
  assert.notEqual(
    archiveKey("ContentVersion", "068000000000001", "001000000000001"),
    archiveKey("ContentVersion", "068000000000001", "001000000000002"),
  );
});

test("Salesforce binary response is streamed to a restricted temporary file", async () => {
  const chunks = [Buffer.from("streamed-"), Buffer.from("salesforce-body")];
  const fetchMock: typeof fetch = async (_input, init) => {
    assert.equal(new Headers(init?.headers).get("authorization"), "Bearer salesforce-token");
    return new Response(new ReadableStream({
      start(controller) {
        for (const chunk of chunks) controller.enqueue(chunk);
        controller.close();
      },
    }));
  };
  const source: ArchiveSource = {
    sourceType: "ContentVersion",
    sourceRecordId: "068000000000001",
    contentDocumentId: "069000000000001",
    fileName: "file.bin",
    fileSizeBytes: 24,
    downloadPath: "/services/data/v63.0/sobjects/ContentVersion/068000000000001/VersionData",
  };
  const client = new SalesforceClient(tokens, tmpdir(), discoveryOptions, fetchMock);
  const downloaded = await client.download(source);
  try {
    assert.equal(downloaded.bytes, Buffer.concat(chunks).length);
    assert.deepEqual(await readFile(downloaded.path), Buffer.concat(chunks));
  } finally {
    await unlink(downloaded.path).catch(() => undefined);
  }
});
