import type { CommandContext } from "@tailor-platform/erp-kit/core";
import { createKyselyMock } from "@tailor-platform/sdk/vitest";
import { describe, expect, it } from "vitest";
import type { Namespace } from "../generated/kysely-tailordb";
import { parseStateToken } from "../lib/slackState";
import { run } from "./beginSlackWorkspaceInstall";

const allowedCtx: CommandContext = {
  actorId: "user-1",
  permissions: [],
};

const SIGNING_SECRET = "test-signing-secret";
const input = { clientId: "client-123", signingSecret: SIGNING_SECRET };

describe("beginSlackWorkspaceInstall", () => {
  it("returns a Slack authorize URL carrying a state token", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    const result = await mock.withTx((trx) => run(trx, input, allowedCtx));

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.authorizeUrl).toContain("https://slack.com/oauth/v2/authorize");
      expect(result.value.authorizeUrl).toContain(
        `state=${encodeURIComponent(result.value.state)}`,
      );
      const parsed = await parseStateToken(result.value.state, SIGNING_SECRET);
      expect(parsed?.userId).toBe("user-1");
    }
  });

  it("signs the state so a different secret cannot verify it", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    const result = await mock.withTx((trx) => run(trx, input, allowedCtx));

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(await parseStateToken(result.value.state, "wrong-secret")).toBeNull();
    }
  });

  it("includes redirect_uri in the authorize URL when supplied", async () => {
    const mock = createKyselyMock<Namespace[keyof Namespace]>();
    const result = await mock.withTx((trx) =>
      run(trx, { ...input, redirectUri: "https://app.example.com/slack/callback" }, allowedCtx),
    );

    expect(result.ok).toBe(true);
    if (result.ok) {
      expect(result.value.authorizeUrl).toContain(
        `redirect_uri=${encodeURIComponent("https://app.example.com/slack/callback")}`,
      );
    }
  });
});
