import { describe, it, expect, vi, beforeEach } from "vitest";

// --- Mocks ---------------------------------------------------------------

const auditCalls: unknown[][] = [];
const updateSetCalls: Record<string, unknown>[] = [];

// Steuert, welchen authTyp das geladene Konto hat (oder kein Treffer).
let selectResult: Array<{ authTyp: "local" | "authentik" }> = [];

function makeTx() {
  return {
    select: () => ({
      from: () => ({
        where: () => Promise.resolve(selectResult),
      }),
    }),
    update: () => ({
      set: (vals: Record<string, unknown>) => {
        updateSetCalls.push(vals);
        return { where: () => Promise.resolve(undefined) };
      },
    }),
  };
}

vi.mock("@/db", () => ({
  db: {
    transaction: (cb: (tx: ReturnType<typeof makeTx>) => Promise<unknown>) =>
      cb(makeTx()),
  },
}));

vi.mock("@/lib/auth/password", () => ({
  hashPassword: (_pw: string) => Promise.resolve("HASHED"),
}));

vi.mock("@/lib/audit", () => ({
  writeAudit: (...args: unknown[]) => {
    auditCalls.push(args);
    return Promise.resolve();
  },
}));

vi.mock("@/lib/geo/nominatim", () => ({
  geocodeAddress: () => Promise.resolve({ status: "fail" }),
}));

// -------------------------------------------------------------------------

import { resetUserPassword } from "@/lib/admin/provisioning";

const USER = "11111111-1111-1111-1111-111111111111";
const ACTOR = "22222222-2222-2222-2222-222222222222";

describe("resetUserPassword", () => {
  beforeEach(() => {
    auditCalls.length = 0;
    updateSetCalls.length = 0;
    selectResult = [];
  });

  it("setzt das Passwort fuer ein lokales Konto zurueck und schreibt Audit", async () => {
    selectResult = [{ authTyp: "local" }];
    const res = await resetUserPassword(USER, ACTOR);
    expect(typeof res.tempPassword).toBe("string");
    expect(res.tempPassword.length).toBeGreaterThan(0);
    expect(updateSetCalls).toEqual([{ passwortHash: "HASHED" }]);
    expect(auditCalls).toHaveLength(1);
    expect(auditCalls[0]?.[1]).toBe("user.reset");
  });

  it("bricht fuer Authentik-Konten ab: kein Hash, kein Audit", async () => {
    selectResult = [{ authTyp: "authentik" }];
    await expect(resetUserPassword(USER, ACTOR)).rejects.toThrow(
      /lokale Konten/i,
    );
    expect(updateSetCalls).toHaveLength(0);
    expect(auditCalls).toHaveLength(0);
  });

  it("bricht ab, wenn das Konto nicht existiert", async () => {
    selectResult = [];
    await expect(resetUserPassword(USER, ACTOR)).rejects.toThrow();
    expect(updateSetCalls).toHaveLength(0);
    expect(auditCalls).toHaveLength(0);
  });
});
