import { beforeEach, describe, expect, expectTypeOf, it } from "vitest";
import type { Id } from "../types";
import { resetAuthExpiredNotification } from "../../auth/authEvents";
import {
  DMS_ACCESS_TOKEN_KEY,
  tokenStore,
} from "../../auth/tokenStore";

class MemoryStorage implements Storage {
  private readonly values = new Map<string, string>();

  get length(): number {
    return this.values.size;
  }

  clear(): void {
    this.values.clear();
  }

  getItem(key: string): string | null {
    return this.values.get(key) ?? null;
  }

  key(index: number): string | null {
    return [...this.values.keys()][index] ?? null;
  }

  removeItem(key: string): void {
    this.values.delete(key);
  }

  setItem(key: string, value: string): void {
    this.values.set(key, value);
  }
}

function installStorage(): void {
  Object.defineProperty(globalThis, "sessionStorage", {
    configurable: true,
    value: new MemoryStorage(),
  });
  Object.defineProperty(globalThis, "localStorage", {
    configurable: true,
    value: new MemoryStorage(),
  });
}

describe("tokenStore", () => {
  beforeEach(() => {
    installStorage();
    resetAuthExpiredNotification();
  });

  it("当前会话 Token 只写入 sessionStorage", () => {
    tokenStore.saveAccessToken("session-token", false);
    expect(sessionStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBe("session-token");
    expect(localStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBeNull();
    expect(tokenStore.getAccessToken()).toBe("session-token");
  });

  it("保持登录 Token 只写入 localStorage", () => {
    tokenStore.saveAccessToken("persistent-token", true);
    expect(localStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBe("persistent-token");
    expect(sessionStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBeNull();
    expect(tokenStore.getAccessToken()).toBe("persistent-token");
  });

  it("切换存储位置时删除旧 Token，清理时删除两处 Token", () => {
    tokenStore.saveAccessToken("persistent-token", true);
    tokenStore.saveAccessToken("session-token", false);
    expect(localStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBeNull();
    tokenStore.clearAccessToken();
    expect(sessionStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBeNull();
    expect(localStorage.getItem(DMS_ACCESS_TOKEN_KEY)).toBeNull();
  });

  it("契约 ID 类型保持为字符串", () => {
    expectTypeOf<Id>().toEqualTypeOf<string>();
    const id: Id = "9223372036854775807";
    expect(id).toBe("9223372036854775807");
  });
});
