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

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

  const defaultOpts = {
    mode: "password" as const,
    length: 16,
    uppercase: true,
    lowercase: true,
    numbers: true,
    symbols: true,
    excludeAmbiguous: false,
    count: 5,
  };

  it("should generate the requested quantity of passwords", async () => {
    const result = await runPasswordGenerator({}, defaultOpts, mockContext);
    expect(result.type).toBe("table");
    if (result.type === "table") {
      expect(result.columns).toEqual(["Password", "Length", "Entropy (bits)"]);
      expect(result.rows).toHaveLength(5);
      expect(result.rows[0][0]).toBeTypeOf("string");
      expect(result.rows[0][1]).toBe(16);
      expect(result.rows[0][2]).toContain("bits");
    }
  });

  it("should enforce selected character rules", async () => {
    // Generate only numbers
    const result = await runPasswordGenerator(
      {},
      {
        ...defaultOpts,
        uppercase: false,
        lowercase: false,
        numbers: true,
        symbols: false,
      },
      mockContext
    );
    if (result.type === "table") {
      result.rows.forEach(row => {
        const password = String(row[0]);
        expect(password).toMatch(/^[0-9]+$/);
      });
    }
  });

  it("should exclude ambiguous characters", async () => {
    const result = await runPasswordGenerator(
      {},
      {
        ...defaultOpts,
        uppercase: true,
        lowercase: true,
        numbers: true,
        symbols: false,
        excludeAmbiguous: true,
        count: 20, // larger sample size
      },
      mockContext
    );
    if (result.type === "table") {
      result.rows.forEach(row => {
        const password = String(row[0]);
        // Ambiguous characters list: l, 1, I, o, 0, O
        expect(password).not.toContain("l");
        expect(password).not.toContain("1");
        expect(password).not.toContain("I");
        expect(password).not.toContain("o");
        expect(password).not.toContain("0");
        expect(password).not.toContain("O");
      });
    }
  });

  it("should generate correct passphrase count and word length", async () => {
    const result = await runPasswordGenerator(
      {},
      {
        ...defaultOpts,
        mode: "passphrase",
        length: 6, // 6 words
        count: 3,
      },
      mockContext
    );
    expect(result.type).toBe("table");
    if (result.type === "table") {
      expect(result.columns).toEqual(["Passphrase", "Length (chars)", "Entropy (bits)"]);
      expect(result.rows).toHaveLength(3);
      const passphrase = String(result.rows[0][0]);
      const words = passphrase.split("-");
      expect(words).toHaveLength(6);
    }
  });

  it("should throw error if all character classes are disabled", async () => {
    await expect(
      runPasswordGenerator(
        {},
        {
          ...defaultOpts,
          uppercase: false,
          lowercase: false,
          numbers: false,
          symbols: false,
        },
        mockContext
      )
    ).rejects.toThrow("Please select at least one character set");
  });
});
