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

describe("CSV <-> JSON Converter Plugin", () => {
  const mockContext: ToolContext = {
    signal: new AbortController().signal,
    reportProgress: vi.fn(),
    logger: {
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
    },
  };

  it("should convert simple CSV to JSON with headers", async () => {
    const csv = "name,age,city\nJohn Doe,30,New York\nJane Smith,25,Los Angeles";
    const result = await runCsvTools(
      { text: csv },
      { mode: "csv-to-json", delimiter: ",", hasHeaderRow: true, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      const parsed = JSON.parse(result.value);
      expect(parsed).toEqual([
        { name: "John Doe", age: "30", city: "New York" },
        { name: "Jane Smith", age: "25", city: "Los Angeles" },
      ]);
    }
  });

  it("should handle commas and newlines inside quoted fields", async () => {
    const csv = 'name,notes\nJohn,"Likes apples, oranges, and bananas"\nJane,"Likes reading\nand cycling"';
    const result = await runCsvTools(
      { text: csv },
      { mode: "csv-to-json", delimiter: ",", hasHeaderRow: true, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      const parsed = JSON.parse(result.value);
      expect(parsed[0].notes).toBe("Likes apples, oranges, and bananas");
      expect(parsed[1].notes).toBe("Likes reading\nand cycling");
    }
  });

  it("should handle escaped quotes inside quotes", async () => {
    const csv = 'name,description\nJohn,"Known as ""The Apple King"""';
    const result = await runCsvTools(
      { text: csv },
      { mode: "csv-to-json", delimiter: ",", hasHeaderRow: true, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      const parsed = JSON.parse(result.value);
      expect(parsed[0].description).toBe('Known as "The Apple King"');
    }
  });

  it("should support custom delimiters like Semicolon", async () => {
    const csv = "name;age\nJohn Doe;30";
    const result = await runCsvTools(
      { text: csv },
      { mode: "csv-to-json", delimiter: ";", hasHeaderRow: true, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      const parsed = JSON.parse(result.value);
      expect(parsed[0]).toEqual({ name: "John Doe", age: "30" });
    }
  });

  it("should parse without header rows", async () => {
    const csv = "John,30\nJane,25";
    const result = await runCsvTools(
      { text: csv },
      { mode: "csv-to-json", delimiter: ",", hasHeaderRow: false, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      const parsed = JSON.parse(result.value);
      expect(parsed).toEqual([
        ["John", "30"],
        ["Jane", "25"],
      ]);
    }
  });

  it("should convert JSON array of objects to CSV", async () => {
    const json = JSON.stringify([
      { name: "John Doe", age: 30, city: "New York" },
      { name: "Jane Smith", age: 25, city: "Los Angeles" },
    ]);
    const result = await runCsvTools(
      { text: json },
      { mode: "json-to-csv", delimiter: ",", hasHeaderRow: true, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      expect(result.value).toBe(
        "name,age,city\nJohn Doe,30,New York\nJane Smith,25,Los Angeles"
      );
    }
  });

  it("should convert JSON array of arrays to CSV", async () => {
    const json = JSON.stringify([
      ["John", 30],
      ["Jane", 25],
    ]);
    const result = await runCsvTools(
      { text: json },
      { mode: "json-to-csv", delimiter: ";", hasHeaderRow: true, prettyJson: false },
      mockContext
    );
    expect(result.type).toBe("text");
    if (result.type === "text") {
      expect(result.value).toBe("John;30\nJane;25");
    }
  });

  it("should throw error for invalid JSON in JSON-to-CSV mode", async () => {
    await expect(
      runCsvTools({ text: "not-json" }, { mode: "json-to-csv", delimiter: ",", hasHeaderRow: true, prettyJson: false }, mockContext)
    ).rejects.toThrow("Invalid input: Not a valid JSON string");
  });

  it("should throw error for non-array JSON", async () => {
    await expect(
      runCsvTools({ text: '{"a": 1}' }, { mode: "json-to-csv", delimiter: ",", hasHeaderRow: true, prettyJson: false }, mockContext)
    ).rejects.toThrow("JSON content must be an array");
  });
});
