import { describe, expect, it, vi } from "vitest";

import {
  createToolType,
  deleteToolType,
  listToolTypes,
  updateToolType,
  validateToolType,
} from "../api/tool-types";

const mockGet = vi.fn();
const mockPost = vi.fn();
const mockPut = vi.fn();
const mockDelete = vi.fn();

vi.mock("../api/client", () => ({
  apiClient: {
    get: (...args: unknown[]) => mockGet(...args),
    post: (...args: unknown[]) => mockPost(...args),
    put: (...args: unknown[]) => mockPut(...args),
    delete: (...args: unknown[]) => mockDelete(...args),
    interceptors: {
      response: {
        use: vi.fn(),
      },
    },
  },
  shouldSkipAuthRedirect: vi.fn(() => false),
}));

describe("tool_types API", () => {
  describe("listToolTypes", () => {
    it("returns tool types with new fields", async () => {
      const mockResponse = {
        data: [
          {
            id: "type-1",
            name: "custom-tool",
            display_name: "Custom Tool",
            definition_type: "dockerfile",
            dockerfile_template: "FROM python:3.11",
            readiness_probe: {
              command: "python --version",
              timeout: 30,
              interval: 2,
            },
            build_context: null,
            created_at: "2024-01-01T00:00:00Z",
            updated_at: "2024-01-01T00:00:00Z",
          },
        ],
      };
      mockGet.mockResolvedValue(mockResponse);

      const result = await listToolTypes();

      expect(result[0].definition_type).toBe("dockerfile");
      expect(result[0].dockerfile_template).toBe("FROM python:3.11");
      expect(result[0].readiness_probe).toEqual({
        command: "python --version",
        timeout: 30,
        interval: 2,
      });
    });

    it("returns compose tool types", async () => {
      const mockResponse = {
        data: [
          {
            id: "type-1",
            name: "code-server",
            definition_type: "compose",
            compose_template: "version: '3.8'",
            dockerfile_template: null,
            build_context: null,
            created_at: "2024-01-01T00:00:00Z",
            updated_at: "2024-01-01T00:00:00Z",
          },
        ],
      };
      mockGet.mockResolvedValue(mockResponse);

      const result = await listToolTypes();

      expect(result[0].definition_type).toBe("compose");
      expect(result[0].dockerfile_template).toBeNull();
    });
  });

  describe("createToolType", () => {
    it("creates tool type with dockerfile", async () => {
      const mockResponse = {
        data: {
          id: "new-type",
          name: "docker-tool",
          definition_type: "dockerfile",
          dockerfile_template: "FROM node:18",
          build_context: null,
          created_at: "2024-01-01T00:00:00Z",
          updated_at: "2024-01-01T00:00:00Z",
        },
      };
      mockPost.mockResolvedValue(mockResponse);

      const result = await createToolType({
        name: "docker-tool",
        display_name: "Docker Tool",
        definition_type: "dockerfile",
        dockerfile_template: "FROM node:18",
        default_port: 3000,
        required_variables: [],
      });

      expect(result.definition_type).toBe("dockerfile");
      expect(mockPost).toHaveBeenCalledWith(
        "/tool-types",
        expect.objectContaining({
          definition_type: "dockerfile",
          dockerfile_template: "FROM node:18",
        })
      );
    });

    it("creates tool type with readiness probe", async () => {
      const mockResponse = {
        data: {
          id: "new-type",
          name: "probed-tool",
          readiness_probe: {
            command: "curl -f http://localhost:8080",
            timeout: 60,
            interval: 3,
          },
          build_context: null,
          created_at: "2024-01-01T00:00:00Z",
          updated_at: "2024-01-01T00:00:00Z",
        },
      };
      mockPost.mockResolvedValue(mockResponse);

      const result = await createToolType({
        name: "probed-tool",
        display_name: "Probed Tool",
        compose_template: "version: '3.8'",
        default_port: 8080,
        required_variables: [],
        readiness_probe: {
          command: "curl -f http://localhost:8080",
          timeout: 60,
          interval: 3,
        },
      });

      expect(result.readiness_probe).toEqual({
        command: "curl -f http://localhost:8080",
        timeout: 60,
        interval: 3,
      });
    });
  });

  describe("validateToolType", () => {
    it("validates tool type by id", async () => {
      const mockResponse = {
        data: { valid: true, errors: [] },
      };
      mockGet.mockResolvedValue(mockResponse);

      const result = await validateToolType("type-1");

      expect(result.valid).toBe(true);
      expect(mockGet).toHaveBeenCalledWith("/tool-types/type-1/validate");
    });

    it("returns validation errors", async () => {
      const mockResponse = {
        data: { valid: false, errors: ["Invalid YAML"] },
      };
      mockGet.mockResolvedValue(mockResponse);

      const result = await validateToolType("type-1");

      expect(result.valid).toBe(false);
      expect(result.errors).toContain("Invalid YAML");
    });
  });

  describe("updateToolType", () => {
    it("updates tool type with new fields", async () => {
      const mockResponse = {
        data: {
          id: "type-1",
          name: "updated-tool",
          definition_type: "dockerfile",
          dockerfile_template: "FROM python:3.11",
          build_context: null,
          created_at: "2024-01-01T00:00:00Z",
          updated_at: "2024-01-01T00:00:00Z",
        },
      };
      mockPut.mockResolvedValue(mockResponse);

      const result = await updateToolType("type-1", {
        definition_type: "dockerfile",
        dockerfile_template: "FROM python:3.11",
      });

      expect(result.definition_type).toBe("dockerfile");
      expect(mockPut).toHaveBeenCalledWith(
        "/tool-types/type-1",
        expect.objectContaining({
          definition_type: "dockerfile",
        })
      );
    });
  });

  describe("deleteToolType", () => {
    it("deletes tool type", async () => {
      mockDelete.mockResolvedValue({ data: undefined });

      await deleteToolType("type-1");

      expect(mockDelete).toHaveBeenCalledWith("/tool-types/type-1");
    });
  });
});
