import { describe, expect, it, afterEach } from "vitest";
import {
  assertEmailChangeAllowed,
  clearEmailChangeAttempts,
  recordEmailChangeAttempt,
} from "@/core/auth/email-change-throttle";
import {
  requestEmailChangeSchema,
  updateAccountProfileSchema,
} from "@/core/validation/schemas";
import { __test as accountTest } from "@/services/account-service";

describe("account profile validation", () => {
  it("accepts name and optional phone", () => {
    expect(
      updateAccountProfileSchema.parse({
        name: "Mukhsin Kidodo",
        phone: "+255700000000",
      }),
    ).toEqual({
      name: "Mukhsin Kidodo",
      phone: "+255700000000",
    });

    expect(
      updateAccountProfileSchema.parse({
        name: "Mukhsin",
        phone: "",
      }),
    ).toEqual({
      name: "Mukhsin",
      phone: "",
    });
  });

  it("rejects short names", () => {
    expect(
      updateAccountProfileSchema.safeParse({ name: "A", phone: "" }).success,
    ).toBe(false);
  });
});

describe("email change validation", () => {
  it("requires a strong current password", () => {
    expect(
      requestEmailChangeSchema.safeParse({
        newEmail: "new@archi.com",
        currentPassword: "short",
      }).success,
    ).toBe(false);

    expect(
      requestEmailChangeSchema.parse({
        newEmail: " New@Archi.com ",
        currentPassword: "long-enough-password",
      }),
    ).toEqual({
      newEmail: "New@Archi.com",
      currentPassword: "long-enough-password",
    });
  });
});

describe("email change tokens", () => {
  it("hashes tokens deterministically without storing the raw value", () => {
    const a = accountTest.hashToken("raw-token-value");
    const b = accountTest.hashToken("raw-token-value");
    const c = accountTest.hashToken("different");
    expect(a).toBe(b);
    expect(a).not.toBe(c);
    expect(a).not.toContain("raw-token");
    expect(a).toHaveLength(64);
  });

  it("scopes identifiers per user", () => {
    expect(accountTest.emailChangeIdentifier("user-1")).toBe(
      "email-change:user-1",
    );
    expect(accountTest.emailChangeIdentifier("user-2")).not.toBe(
      accountTest.emailChangeIdentifier("user-1"),
    );
  });
});

describe("email change throttle", () => {
  afterEach(() => {
    clearEmailChangeAttempts();
  });

  it("allows a small burst then rate limits", () => {
    const key = "email-change:user-test";
    expect(assertEmailChangeAllowed(key).ok).toBe(true);
    recordEmailChangeAttempt(key);
    expect(assertEmailChangeAllowed(key).ok).toBe(true);
    recordEmailChangeAttempt(key);
    expect(assertEmailChangeAllowed(key).ok).toBe(true);
    recordEmailChangeAttempt(key);
    const blocked = assertEmailChangeAllowed(key);
    expect(blocked.ok).toBe(false);
    if (!blocked.ok) {
      expect(blocked.retryAfterSec).toBeGreaterThan(0);
    }
  });
});
