import type { ToolInput } from "../../core/io/input-types";
import type { ToolResult } from "../../core/io/output-types";
import type { ToolContext } from "../../core/plugins/plugin-types";

function base64urlDecode(str: string): string {
  const base64 = str.replace(/-/g, "+").replace(/_/g, "/");
  const paddingNeeded = (4 - (base64.length % 4)) % 4;
  const padded = base64 + "=".repeat(paddingNeeded);
  
  const binary = atob(padded);
  const bytes = new Uint8Array(binary.length);
  for (let i = 0; i < binary.length; i++) {
    bytes[i] = binary.charCodeAt(i);
  }
  return new TextDecoder().decode(bytes);
}

export async function runJwtDecoder(
  input: ToolInput,
  _options: unknown,
  context: ToolContext
): Promise<ToolResult> {
  const token = (input.text ?? "").trim();
  if (!token) {
    throw new Error("Please enter a JWT token to decode.");
  }

  context.reportProgress({ percentage: 20, message: "Parsing token parts..." });

  const parts = token.split(".");
  if (parts.length !== 3) {
    throw new Error("Invalid JWT token format. A JWT must consist of three parts (header, payload, signature) separated by dots.");
  }

  const [headerB64, payloadB64, signatureHex] = parts;

  context.reportProgress({ percentage: 50, message: "Decoding JSON content..." });

  let header: Record<string, unknown>;
  let payload: Record<string, unknown>;

  try {
    const decodedHeader = base64urlDecode(headerB64);
    header = JSON.parse(decodedHeader);
  } catch (err) {
    throw new Error("Failed to decode JWT Header: invalid Base64URL encoding or malformed JSON content.");
  }

  try {
    const decodedPayload = base64urlDecode(payloadB64);
    payload = JSON.parse(decodedPayload);
  } catch (err) {
    throw new Error("Failed to decode JWT Payload: invalid Base64URL encoding or malformed JSON content.");
  }

  context.reportProgress({ percentage: 85, message: "Checking claims..." });

  let expiresAt: string | null = null;
  let issuedAt: string | null = null;
  let status: "valid" | "expired" = "valid";
  let primary = "Valid (No Expiration claim)";

  if (typeof payload.exp === "number") {
    const expTime = payload.exp * 1000;
    expiresAt = new Date(expTime).toISOString();
    if (Date.now() > expTime) {
      status = "expired";
      primary = `Expired (at ${expiresAt})`;
    } else {
      primary = `Valid (Expires: ${expiresAt})`;
    }
  }

  if (typeof payload.iat === "number") {
    issuedAt = new Date(payload.iat * 1000).toISOString();
  }

  context.reportProgress({ percentage: 100, message: "Done" });

  return {
    type: "json",
    value: {
      primary,
      status,
      expiresAt,
      issuedAt,
      header,
      payload,
      signature: signatureHex || "(empty)",
    },
  };
}
