import { describe, it, expect, vi } from "vitest";
import { runJwtDecoder } from "./run";
import type { ToolContext } from "../../core/plugins/plugin-types";

describe("JWT Decoder Plugin", () => {
  const mockContext: ToolContext = {
    signal: new AbortController().signal,
    reportProgress: vi.fn(),
    logger: {
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    },
  };

  // {"alg":"HS256","typ":"JWT"} -> eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  // {"sub":"123","name":"John Doe","iat":1516239022} -> eyJzdWIiOiIxMjMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9
  const validNoExp = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJuYW1lIjoiSm9obiBEb2UiLCJpYXQiOjE1MTYyMzkwMjJ9.sig";

  // {"sub":"123","exp":32503680000} (Year 3000) -> eyJzdWIiOiIxMjMiLCJleHAiOjMyNTAzNjgwMDAwfQ
  const futureExp = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjMyNTAzNjgwMDAwfQ.sig";

  // {"sub":"123","exp":946684800} (Year 2000) -> eyJzdWIiOiIxMjMiLCJleHAiOjk0NjY4NDgwMH0
  const expiredExp = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjMiLCJleHAiOjk0NjY4NDgwMH0.sig";

  it("should decode a valid JWT without exp claim", async () => {
    const result = await runJwtDecoder({ text: validNoExp }, {}, mockContext);
    expect(result.type).toBe("json");
    if (result.type === "json") {
      const data = result.value as any;
      expect(data.status).toBe("valid");
      expect(data.primary).toContain("Valid (No Expiration claim)");
      expect(data.header.alg).toBe("HS256");
      expect(data.payload.sub).toBe("123");
      expect(data.issuedAt).toBe("2018-01-18T01:30:22.000Z");
      expect(data.expiresAt).toBeNull();
    }
  });

  it("should decode a valid JWT with future exp claim", async () => {
    const result = await runJwtDecoder({ text: futureExp }, {}, mockContext);
    expect(result.type).toBe("json");
    if (result.type === "json") {
      const data = result.value as any;
      expect(data.status).toBe("valid");
      expect(data.primary).toContain("Valid (Expires:");
      expect(data.expiresAt).toBe("3000-01-01T00:00:00.000Z");
    }
  });

  it("should decode an expired JWT with past exp claim", async () => {
    const result = await runJwtDecoder({ text: expiredExp }, {}, mockContext);
    expect(result.type).toBe("json");
    if (result.type === "json") {
      const data = result.value as any;
      expect(data.status).toBe("expired");
      expect(data.primary).toContain("Expired (at");
      expect(data.expiresAt).toBe("2000-01-01T00:00:00.000Z");
    }
  });

  it("should throw error for empty token", async () => {
    await expect(
      runJwtDecoder({ text: "" }, {}, mockContext)
    ).rejects.toThrow("Please enter a JWT token to decode.");
  });

  it("should throw error for malformed token format", async () => {
    await expect(
      runJwtDecoder({ text: "one.two" }, {}, mockContext)
    ).rejects.toThrow("A JWT must consist of three parts");
  });

  it("should throw error for invalid JSON payload", async () => {
    // Header ok, payload invalid base64/json: "invalid" -> aW52YWxpZA==
    const invalidJson = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.aW52YWxpZA.sig";
    await expect(
      runJwtDecoder({ text: invalidJson }, {}, mockContext)
    ).rejects.toThrow("Failed to decode JWT Payload: invalid Base64URL encoding or malformed JSON content.");
  });
});
