import { ContextKeysManager, REFERENCE_NAMESPACE, NOTHING } from "../..";
import { buildNamespaceKey } from "../../utils";
import { StorageType } from "../../consts";

describe("Context Keys Manager - getKeyByReference", () => {
  it("returns null if reference-storage failed", async () => {
    // setup
    const key = "key";
    const namespace = "namespace";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedReferenceStorage = {
      getItem: jest.fn().mockRejectedValueOnce(error),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
      referenceStorage: mockedReferenceStorage,
    });

    // run
    const result = await contextManager.getKeyByReference(key, namespace);

    // verify
    expect(result).toEqual(NOTHING);

    expect(mockedLogger.warn).toHaveBeenCalledTimes(1);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key, namespace },
    });

    expect(mockedSessionStorage.getItem).not.toHaveBeenCalled();
    expect(mockedLocalStorage.getItem).not.toHaveBeenCalled();
    expect(mockedSecureStorage.getItem).not.toHaveBeenCalled();

    expect(mockedReferenceStorage.getItem).toHaveBeenCalledWith(
      buildNamespaceKey(key, namespace),
      REFERENCE_NAMESPACE
    );
  });

  it("returns null if from session-storage failed", async () => {
    // setup
    const key = "key";
    const namespace = "namespace";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn().mockRejectedValueOnce(error),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedReferenceStorage = {
      getItem: jest.fn().mockResolvedValueOnce(StorageType.session),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
      referenceStorage: mockedReferenceStorage,
    });

    // run
    const result = await contextManager.getKeyByReference(key, namespace);

    // verify
    expect(result).toEqual(NOTHING);

    expect(mockedLogger.warn).toHaveBeenCalledTimes(1);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key, namespace },
    });

    expect(mockedSessionStorage.getItem).toHaveBeenCalledWith(key, namespace);
    expect(mockedLocalStorage.getItem).not.toHaveBeenCalled();
    expect(mockedSecureStorage.getItem).not.toHaveBeenCalled();

    expect(mockedReferenceStorage.getItem).toHaveBeenCalledWith(
      buildNamespaceKey(key, namespace),
      REFERENCE_NAMESPACE
    );
  });

  it("returns null if from local-storage failed", async () => {
    // setup
    const key = "key";
    const namespace = "namespace";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedLocalStorage = {
      getItem: jest.fn().mockRejectedValueOnce(error),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedSecureStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedReferenceStorage = {
      getItem: jest.fn().mockResolvedValueOnce(StorageType.local),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
      referenceStorage: mockedReferenceStorage,
    });

    // run
    const result = await contextManager.getKeyByReference(key, namespace);

    // verify
    expect(result).toEqual(NOTHING);

    expect(mockedLogger.warn).toHaveBeenCalledTimes(1);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key, namespace },
    });

    expect(mockedSessionStorage.getItem).not.toHaveBeenCalled();
    expect(mockedLocalStorage.getItem).toHaveBeenCalledWith(key, namespace);
    expect(mockedSecureStorage.getItem).not.toHaveBeenCalled();

    expect(mockedReferenceStorage.getItem).toHaveBeenCalledWith(
      buildNamespaceKey(key, namespace),
      REFERENCE_NAMESPACE
    );
  });

  it("returns null if from secure-storage failed", async () => {
    // setup
    const key = "key";
    const namespace = "namespace";
    const error = Error("oops");

    const mockedLogger = {
      warn: jest.fn(),
    };

    const mockedSessionStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedLocalStorage = {
      getItem: jest.fn(),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedSecureStorage = {
      getItem: jest.fn().mockRejectedValueOnce(error),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const mockedReferenceStorage = {
      getItem: jest.fn().mockResolvedValueOnce(StorageType.secure),
      setItem: jest.fn(),
      removeItem: jest.fn(),
    };

    const contextManager = new ContextKeysManager({
      logger: mockedLogger,
      sessionStorage: mockedSessionStorage,
      localStorage: mockedLocalStorage,
      secureStorage: mockedSecureStorage,
      referenceStorage: mockedReferenceStorage,
    });

    // run
    const result = await contextManager.getKeyByReference(key, namespace);

    // verify
    expect(result).toEqual(NOTHING);

    expect(mockedLogger.warn).toHaveBeenCalledTimes(1);

    expect(mockedLogger.warn).toHaveBeenCalledWith({
      message: error.message,
      data: { key, namespace },
    });

    expect(mockedSessionStorage.getItem).not.toHaveBeenCalled();
    expect(mockedLocalStorage.getItem).not.toHaveBeenCalled();
    expect(mockedSecureStorage.getItem).toHaveBeenCalledWith(key, namespace);

    expect(mockedReferenceStorage.getItem).toHaveBeenCalledWith(
      buildNamespaceKey(key, namespace),
      REFERENCE_NAMESPACE
    );
  });
});
