import { describe, it, expect } from "vitest";
import { z } from "zod";
import { authorize } from "@/authorize";
import { defineRealtimeChannel } from "@/realtime-channel";

const schema = z.object({}).strict();

describe("authorize", () => {
  describe("public", () => {
    const ch = defineRealtimeChannel("a", schema, { scope: "public" });
    it("allows anonymous", async () => {
      expect(await authorize(ch, {}, null)).toBe(true);
    });
    it("allows authenticated", async () => {
      expect(await authorize(ch, {}, { userId: "u1", roles: [] })).toBe(true);
    });
  });

  describe("authenticated", () => {
    const ch = defineRealtimeChannel("a", schema, { scope: "authenticated" });
    it("rejects anonymous", async () => {
      expect(await authorize(ch, {}, null)).toBe(false);
    });
    it("allows any user", async () => {
      expect(await authorize(ch, {}, { userId: "u1", roles: [] })).toBe(true);
    });
  });

  describe("{ role }", () => {
    const ch = defineRealtimeChannel("a", schema, { scope: { role: "admin" } });
    it("rejects anonymous", async () => {
      expect(await authorize(ch, {}, null)).toBe(false);
    });
    it("rejects user without role", async () => {
      expect(await authorize(ch, {}, { userId: "u1", roles: ["editor"] })).toBe(false);
    });
    it("allows user with role", async () => {
      expect(await authorize(ch, {}, { userId: "u1", roles: ["admin", "editor"] })).toBe(true);
    });
  });

  describe("{ userScoped }", () => {
    const ch = defineRealtimeChannel("a", schema, {
      scope: { userScoped: true, template: "notifications.user.{userId}" },
    });
    it("rejects anonymous", async () => {
      expect(await authorize(ch, { userId: "u1" }, null)).toBe(false);
    });
    it("rejects user requesting someone else's channel", async () => {
      expect(
        await authorize(ch, { userId: "u_other" }, { userId: "u1", roles: [] }),
      ).toBe(false);
    });
    it("allows user requesting own channel", async () => {
      expect(
        await authorize(ch, { userId: "u1" }, { userId: "u1", roles: [] }),
      ).toBe(true);
    });
  });
});
