import { describe, it, expect, vi, beforeEach } from "vitest";
import { NextRequest } from "next/server";

const mockAdminSession = { user: { id: "admin-1", role: "admin" } };

vi.mock("next/headers", () => ({
  headers: vi.fn().mockResolvedValue(new Headers()),
}));

vi.mock("@/lib/auth/server", () => ({
  auth: { api: { getSession: vi.fn() } },
}));

vi.mock("@/lib/site-settings", () => ({
  setSiteSetting: vi.fn().mockResolvedValue(undefined),
}));

const { mockSelectChain, mockInsertValues } = vi.hoisted(() => {
  const mockSelectChain = {
    from: vi.fn().mockReturnThis(),
    where: vi.fn().mockResolvedValue([{ role: "admin" }]),
  };
  return { mockSelectChain, mockInsertValues: vi.fn().mockResolvedValue(undefined) };
});

vi.mock("@epicure/db", () => ({
  db: {
    select: vi.fn(() => mockSelectChain),
    insert: vi.fn(() => ({ values: mockInsertValues })),
  },
  users: { id: "id", role: "role" },
  auditLogs: {},
  eq: vi.fn((a, b) => ({ a, b, op: "eq" })),
}));

const { auth } = await import("@/lib/auth/server");
const { setSiteSetting } = await import("@/lib/site-settings");
import { PUT } from "../route";

function makeRequest(body: unknown) {
  return new NextRequest("http://localhost/api/v1/admin/settings", {
    method: "PUT",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(body),
  });
}

beforeEach(() => {
  vi.clearAllMocks();
  vi.mocked(auth.api.getSession).mockResolvedValue(mockAdminSession as never);
  mockSelectChain.where.mockResolvedValue([{ role: "admin" }]);
});

describe("PUT /api/v1/admin/settings", () => {
  it("returns 403 when caller is not an admin", async () => {
    mockSelectChain.where.mockResolvedValue([{ role: "user" }]);
    const res = await PUT(makeRequest({ OPENAI_API_KEY: "sk-1" }));
    expect(res.status).toBe(403);
  });

  it("returns 403 when there is no session", async () => {
    vi.mocked(auth.api.getSession).mockResolvedValue(null as never);
    const res = await PUT(makeRequest({ OPENAI_API_KEY: "sk-1" }));
    expect(res.status).toBe(403);
  });

  it("updates allowed keys and writes an audit log", async () => {
    const res = await PUT(makeRequest({ OPENAI_API_KEY: "sk-1" }));
    expect(res.status).toBe(200);
    expect(vi.mocked(setSiteSetting)).toHaveBeenCalledWith("OPENAI_API_KEY", "sk-1", "admin-1");
    expect(mockInsertValues).toHaveBeenCalled();
  });

  it("silently ignores keys not in the allow-list", async () => {
    const res = await PUT(makeRequest({ NOT_A_REAL_KEY: "x" }));
    expect(res.status).toBe(200);
    expect(vi.mocked(setSiteSetting)).not.toHaveBeenCalled();
    expect(mockInsertValues).not.toHaveBeenCalled();
  });
});
