import { describe, expect, test } from "bun:test";

import type { CheckerValidationInput } from "../../../../../src/server/checker/runner/types";

import { validateCommandConfig } from "../../../../../src/server/checker/runner/cmd/validate";
import { validateDbConfig } from "../../../../../src/server/checker/runner/db/validate";
import { validateHttpConfig } from "../../../../../src/server/checker/runner/http/validate";
import { validatePingConfig } from "../../../../../src/server/checker/runner/icmp/validate";
import { validateLlmConfig } from "../../../../../src/server/checker/runner/llm/validate";
import { validateTcpConfig } from "../../../../../src/server/checker/runner/tcp/validate";
import { validateUdpConfig } from "../../../../../src/server/checker/runner/udp/validate";

function input(target: Record<string, unknown>): CheckerValidationInput {
  return { defaults: {}, targets: [target as CheckerValidationInput["targets"][number]] };
}

describe("ValueMatcher primitive shorthand in checker validators", () => {
  test("accepts shorthand for all checker ValueMatcher fields", () => {
    const targets = [
      {
        expect: { durationMs: 100 },
        http: { url: "https://example.com" },
        id: "http",
        type: "http",
        validate: validateHttpConfig,
      },
      {
        expect: { durationMs: 100 },
        id: "tcp",
        tcp: { host: "127.0.0.1", port: 80 },
        type: "tcp",
        validate: validateTcpConfig,
      },
      {
        expect: { durationMs: 100, responseSize: 1, sourceHost: "127.0.0.1", sourcePort: 53 },
        id: "udp",
        type: "udp",
        udp: { host: "127.0.0.1", port: 53 },
        validate: validateUdpConfig,
      },
      {
        expect: { avgLatencyMs: 1, durationMs: 100, maxLatencyMs: 2, packetLossPercent: 0 },
        icmp: { host: "127.0.0.1" },
        id: "icmp",
        type: "icmp",
        validate: validatePingConfig,
      },
      {
        cmd: { exec: "true" },
        expect: { durationMs: 100 },
        id: "cmd",
        type: "cmd",
        validate: validateCommandConfig,
      },
      {
        db: { url: "sqlite://:memory:" },
        expect: { durationMs: 100, rowCount: 1 },
        id: "db",
        type: "db",
        validate: validateDbConfig,
      },
      {
        expect: {
          durationMs: 100,
          finishReason: "stop",
          rawFinishReason: null,
          stream: { firstTokenMs: 10 },
          usage: { inputTokens: 1, outputTokens: 2, totalTokens: 3 },
        },
        id: "llm",
        llm: {
          mode: "stream",
          model: "test-model",
          prompt: "hello",
          provider: "openai",
          url: "https://example.com/v1/chat/completions",
        },
        type: "llm",
        validate: validateLlmConfig,
      },
    ];

    for (const target of targets) {
      const { validate, ...config } = target;
      const original = structuredClone(config);

      expect(validate(input(config))).toHaveLength(0);
      expect(config).toEqual(original);
    }
  });

  test("rejects array and object shorthand while accepting explicit equals", () => {
    const arrayTarget = {
      expect: { durationMs: [1, 2] },
      http: { url: "https://example.com" },
      id: "array",
      type: "http",
    };
    const objectTarget = {
      expect: { durationMs: { foo: "bar" } },
      http: { url: "https://example.com" },
      id: "object",
      type: "http",
    };
    const equalsObjectTarget = {
      expect: { durationMs: { equals: { foo: "bar" } } },
      http: { url: "https://example.com" },
      id: "equals-object",
      type: "http",
    };

    expect(validateHttpConfig(input(arrayTarget)).some((issue) => issue.path.includes("durationMs"))).toBe(true);
    expect(validateHttpConfig(input(objectTarget)).some((issue) => issue.code === "unknown-matcher")).toBe(true);
    expect(validateHttpConfig(input(equalsObjectTarget))).toHaveLength(0);
  });
});
