/**
 * Unit tests for `getAdminUser()`. The dev_session cookie bypass has been
 * removed; the only path into the admin is through a real Neon Auth
 * session. These tests mock the `getSession()` function and the DB layer
 * to exercise the lookup.
 */
import { describe, it, expect, vi, beforeEach } from "vitest";

// Use vi.hoisted to ensure mocks are available when vi.mock runs
const { mockDb, mockWithPlatformAdmin, mockGetSession, mockCookies } = vi.hoisted(() => {
  const mockDb = {
    select: vi.fn(),
  };
  return {
    mockDb,
    mockWithPlatformAdmin: vi.fn(async (fn: (db: typeof mockDb) => Promise<unknown>) => {
      return fn(mockDb);
    }),
    mockGetSession: vi.fn(),
    mockCookies: vi.fn(),
  };
});

// Stub the server-only guard so the module can be imported under vitest.
vi.mock("server-only", () => ({}));

// Mock the Drizzle client wrapper
vi.mock("@/db/client", () => ({
  withPlatformAdmin: mockWithPlatformAdmin,
}));

// Mock the getSession() function
vi.mock("@/lib/auth", () => ({
  getSession: mockGetSession,
}));

// Mock cookies() so we don't read a real cookie store
vi.mock("next/headers", () => ({
  cookies: mockCookies,
}));

import { getAdminUser, buildDevAdmin, permissionsForRole } from "@/lib/admin-permissions";

const cookieStore = { get: vi.fn() };

beforeEach(() => {
  mockDb.select.mockReset();
  mockWithPlatformAdmin.mockReset();
  mockGetSession.mockReset();
  mockCookies.mockImplementation(() => Promise.resolve(cookieStore));
  cookieStore.get.mockReturnValue(undefined);
});

describe("getAdminUser()", () => {
  it("returns null when there is no Neon Auth session", async () => {
    mockGetSession.mockResolvedValue({ data: null });
    const u = await getAdminUser();
    expect(u).toBeNull();
  });

  it("returns null when the session has no email", async () => {
    mockGetSession.mockResolvedValue({ data: { user: { name: "no-email" } } });
    const u = await getAdminUser();
    expect(u).toBeNull();
  });

  it("returns null when the email is not in the users table", async () => {
    mockGetSession.mockResolvedValue({ data: { user: { email: "unknown@example.com" } } });
    // First select: users. Returns empty.
    mockDb.select.mockReturnValueOnce({
      from: () => ({
        where: () => ({
          limit: async () => [],
        }),
      }),
    });
    const u = await getAdminUser();
    expect(u).toBeNull();
  });

  it("returns null when the user exists but has no admin_user_brands row", async () => {
    mockGetSession.mockResolvedValue({ data: { user: { email: "no-brand@example.com" } } });
    // First select: users — returns the user
    mockDb.select
      .mockReturnValueOnce({
        from: () => ({
          where: () => ({
            limit: async () => [
              {
                id: "user-1",
                email: "no-brand@example.com",
                name: "No Brand",
                role: "brand_admin",
              },
            ],
          }),
        }),
      })
      // Second select: adminUserBrands — returns empty
      .mockReturnValueOnce({
        from: () => ({
          innerJoin: () => ({
            where: () => ({
              limit: async () => [],
            }),
          }),
        }),
      });
    const u = await getAdminUser();
    expect(u).toBeNull();
  });

  it("returns a fully-populated AdminUser for a provisioned brand_admin", async () => {
    mockGetSession.mockResolvedValue({ data: { user: { email: "admin@tuxedo.example" } } });
    mockDb.select
      .mockReturnValueOnce({
        from: () => ({
          where: () => ({
            limit: async () => [
              {
                id: "user-tux",
                email: "admin@tuxedo.example",
                name: "Tux Admin",
                role: "brand_admin",
              },
            ],
          }),
        }),
      })
      .mockReturnValueOnce({
        from: () => ({
          innerJoin: () => ({
            where: () => ({
              limit: async () => [
                {
                  brandId: "brand-tux",
                  brandName: "Tuxedo Citrus",
                  brandSlug: "tuxedo",
                  role: "brand_admin",
                },
              ],
            }),
          }),
        }),
      });

    const u = await getAdminUser();
    expect(u).not.toBeNull();
    expect(u?.email).toBe("admin@tuxedo.example");
    expect(u?.brand_id).toBe("brand-tux");
    expect(u?.brand_slug).toBe("tuxedo");
    expect(u?.role).toBe("brand_admin");
    expect(u?.can_manage_products).toBe(true);
    expect(u?.can_manage_team).toBe(true);
  });
});

describe("buildDevAdmin()", () => {
  it("returns a platform_admin with no brand", () => {
    const u = buildDevAdmin("platform_admin");
    expect(u.role).toBe("platform_admin");
    expect(u.brand_id).toBeNull();
    expect(u.brand_slug).toBeNull();
    expect(u.can_manage_billing).toBe(true);
  });

  it("returns a brand_admin tied to the tuxedo brand", () => {
    const u = buildDevAdmin("brand_admin");
    expect(u.role).toBe("brand_admin");
    expect(u.brand_slug).toBe("tuxedo");
    expect(u.can_manage_users).toBe(false);
  });

  it("returns a store_employee with limited permissions", () => {
    const u = buildDevAdmin("store_employee");
    expect(u.role).toBe("store_employee");
    expect(u.can_manage_products).toBe(false);
    expect(u.can_manage_orders).toBe(true);
    expect(u.can_manage_billing).toBe(false);
  });
});

describe("permissionsForRole()", () => {
  it("platform_admin can do everything", () => {
    const p = permissionsForRole("platform_admin");
    expect(Object.values(p).every((v) => v === true)).toBe(true);
  });
  it("brand_admin can manage most things but not users", () => {
    const p = permissionsForRole("brand_admin");
    expect(p.can_manage_users).toBe(false);
    expect(p.can_manage_billing).toBe(true);
  });
  it("store_employee is restricted to orders + pickup", () => {
    const p = permissionsForRole("store_employee");
    expect(p.can_manage_orders).toBe(true);
    expect(p.can_manage_pickup).toBe(true);
    expect(p.can_manage_products).toBe(false);
    expect(p.can_manage_billing).toBe(false);
  });
});