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

vi.mock("next/headers", () => ({
  headers: async () => new Headers({ "x-forwarded-for": "203.0.113.7" }),
  cookies: async () => ({ get: () => undefined, set: () => {}, delete: () => {} }),
}));

import {
  getAdminLockState,
  isAdminAuthConfigured,
  isPasswordValid,
  registerFailedAdminAttempt,
  resetAdminFailedAttempts,
} from "@/lib/admin-auth";

afterEach(() => {
  vi.unstubAllEnvs();
});

describe("admin auth configuration", () => {
  it("is configured only when both password and secret are set", () => {
    vi.stubEnv("ADMIN_PASSWORD", "");
    vi.stubEnv("ADMIN_AUTH_SECRET", "");
    expect(isAdminAuthConfigured()).toBe(false);

    vi.stubEnv("ADMIN_PASSWORD", "pw");
    vi.stubEnv("ADMIN_AUTH_SECRET", "");
    expect(isAdminAuthConfigured()).toBe(false);

    vi.stubEnv("ADMIN_PASSWORD", "pw");
    vi.stubEnv("ADMIN_AUTH_SECRET", "secret");
    expect(isAdminAuthConfigured()).toBe(true);
  });
});

describe("isPasswordValid", () => {
  it("returns false when auth is not configured", () => {
    vi.stubEnv("ADMIN_PASSWORD", "");
    vi.stubEnv("ADMIN_AUTH_SECRET", "");
    expect(isPasswordValid("anything")).toBe(false);
  });

  it("accepts the correct password and rejects wrong ones", () => {
    vi.stubEnv("ADMIN_PASSWORD", "s3cret-password");
    vi.stubEnv("ADMIN_AUTH_SECRET", "hmac-secret");
    expect(isPasswordValid("s3cret-password")).toBe(true);
    expect(isPasswordValid("wrong")).toBe(false);
    expect(isPasswordValid("s3cret-passwordX")).toBe(false); // length mismatch
  });
});

describe("login lockout", () => {
  it("locks the IP after the failed-attempt threshold", async () => {
    expect((await getAdminLockState()).locked).toBe(false);

    for (let i = 0; i < 4; i += 1) {
      const state = await registerFailedAdminAttempt();
      expect(state.locked).toBe(false);
    }
    expect((await getAdminLockState()).locked).toBe(false);

    const fifth = await registerFailedAdminAttempt();
    expect(fifth.locked).toBe(true);
    expect(fifth.remainingSeconds).toBeGreaterThan(0);

    const lockState = await getAdminLockState();
    expect(lockState.locked).toBe(true);
    expect(lockState.remainingSeconds).toBeGreaterThan(0);
    expect(lockState.remainingSeconds).toBeLessThanOrEqual(15 * 60);
  });

  it("clears the lock on reset", async () => {
    for (let i = 0; i < 5; i += 1) {
      await registerFailedAdminAttempt();
    }
    expect((await getAdminLockState()).locked).toBe(true);

    await resetAdminFailedAttempts();
    expect((await getAdminLockState()).locked).toBe(false);
  });
});
