import { get, patch, post, put } from "@toruslabs/http-helpers";
import { describe, expect, test, vi } from "vitest";

import { BaseSessionManager } from "../src/base";
import { ApiRequestParams } from "../src/interfaces";

// Concrete implementation for testing
type TestSessionData = { testData: string };
class TestSessionManager extends BaseSessionManager<TestSessionData> {
  async createSession(_data: TestSessionData): Promise<string> {
    return Promise.resolve("");
  }

  async authorizeSession(): Promise<TestSessionData> {
    return Promise.resolve({ testData: "" });
  }

  async updateSession(): Promise<void> {
    return Promise.resolve();
  }

  async invalidateSession(): Promise<boolean> {
    return Promise.resolve(true);
  }

  request<T>({ url, method, data, headers }: ApiRequestParams): Promise<T> {
    return super.request({ url, method, data, headers });
  }
}

vi.mock("@toruslabs/http-helpers");

describe("BaseSessionManager", () => {
  test("should throw error if sessionId is not set", () => {
    const sessionManager = new TestSessionManager();
    expect(() => sessionManager.checkSessionParams()).toThrow("Session id is required");
  });
  test("should pad sessionId with 0s if it is less than 64 characters", () => {
    const sessionManager = new TestSessionManager();
    sessionManager.sessionId = "1234567890";
    sessionManager.checkSessionParams();
    expect(sessionManager.sessionId).toBe("0000000000000000000000000000000000000000000000000000001234567890");
  });
  test("should keep sessionId as is if it is 64 characters", () => {
    const sessionManager = new TestSessionManager();
    sessionManager.sessionId = "0000000000123456789012345678901234567890123456789012345678901234";
    sessionManager.checkSessionParams();
    expect(sessionManager.sessionId).toBe("0000000000123456789012345678901234567890123456789012345678901234");
  });
  test("should pad sessionId to 64 characters if it is greater than 64 characters", () => {
    const sessionManager = new TestSessionManager();
    sessionManager.sessionId = "0000000000123456789012345678901234567890123456789012345678901234567";
    sessionManager.checkSessionParams();
    expect(sessionManager.sessionId).toBe("0000000000123456789012345678901234567890123456789012345678901234");
  });
  test("request method calls GET, POST, PUT, PATCH correctly", () => {
    const sessionManager = new TestSessionManager();

    sessionManager.request({ url: "https://example.com", method: "GET" });
    expect(get).toHaveBeenCalledWith("https://example.com", { headers: {} });

    sessionManager.request({ url: "https://example.com", method: "POST", data: { test: "test" } });
    expect(post).toHaveBeenCalledWith("https://example.com", { test: "test" }, { headers: {} });

    sessionManager.request({ url: "https://example.com", method: "PUT", data: { test: "test" } });
    expect(put).toHaveBeenCalledWith("https://example.com", { test: "test" }, { headers: {} });

    sessionManager.request({ url: "https://example.com", method: "PATCH", data: { test: "test" } });
    expect(patch).toHaveBeenCalledWith("https://example.com", { test: "test" }, { headers: {} });
  });
  test("request method throws error if method is invalid", () => {
    const sessionManager = new TestSessionManager();
    expect(() => sessionManager.request({ url: "https://example.com", method: "INVALID" })).toThrow("Invalid method type");
  });
});
