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

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

  it("should convert decimal to hexadecimal", async () => {
    const result = await runNumberBase(
      { text: "255" },
      { fromBase: "10", toBase: "16" },
      mockContext
    );
    expect(result.type).toBe("json");
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.decimal).toBe("255");
    expect(value.hexadecimal).toBe("0xFF");
    expect(value.primary).toBe("0xFF");
  });

  it("should convert hexadecimal to decimal", async () => {
    const result = await runNumberBase(
      { text: "0xFF" },
      { fromBase: "16", toBase: "10" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.decimal).toBe("255");
    expect(value.primary).toBe("255");
  });

  it("should convert decimal to binary", async () => {
    const result = await runNumberBase(
      { text: "10" },
      { fromBase: "10", toBase: "2" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.binary).toBe("0b1010");
    expect(value.primary).toBe("0b1010");
  });

  it("should convert binary to decimal", async () => {
    const result = await runNumberBase(
      { text: "1010" },
      { fromBase: "2", toBase: "10" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.decimal).toBe("10");
  });

  it("should convert decimal to octal", async () => {
    const result = await runNumberBase(
      { text: "64" },
      { fromBase: "10", toBase: "8" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.octal).toBe("0o100");
  });

  it("should return all base representations in every conversion", async () => {
    const result = await runNumberBase(
      { text: "42" },
      { fromBase: "10", toBase: "16" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.binary).toBeDefined();
    expect(value.octal).toBeDefined();
    expect(value.decimal).toBeDefined();
    expect(value.hexadecimal).toBeDefined();
  });

  it("should throw on empty input", async () => {
    await expect(
      runNumberBase({ text: "" }, { fromBase: "10", toBase: "16" }, mockContext)
    ).rejects.toThrow("No number provided");
  });

  it("should throw on invalid number for given base", async () => {
    await expect(
      runNumberBase({ text: "xyz" }, { fromBase: "10", toBase: "16" }, mockContext)
    ).rejects.toThrow();
  });

  it("should handle zero", async () => {
    const result = await runNumberBase(
      { text: "0" },
      { fromBase: "10", toBase: "2" },
      mockContext
    );
    const value = (result as { type: "json"; value: Record<string, unknown> }).value;
    expect(value.decimal).toBe("0");
    expect(value.binary).toBe("0b0");
  });
});
