import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { mkdir, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";

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

import { loadConfig } from "../../../../../src/server/checker/config-loader";

describe("loadConfig with ws checker", () => {
  let tempDir: string;

  beforeAll(async () => {
    tempDir = join(tmpdir(), `ws-cfg-test-${Date.now()}`);
    await mkdir(tempDir, { recursive: true });
  });

  afterAll(async () => {
    await rm(tempDir, { force: true, recursive: true });
  });

  test("解析最简 ws 配置", async () => {
    const configPath = join(tempDir, "minimal-ws.yaml");
    await writeFile(
      configPath,
      `targets:
  - id: "ws-test"
    type: ws
    ws:
      url: "ws://example.com/ws"
`,
    );

    const config = await loadConfig(configPath);
    expect(config.targets).toHaveLength(1);
    const t = config.targets[0]! as ResolvedWsTarget;
    expect(t.type).toBe("ws");
    expect(t.id).toBe("ws-test");
    expect(t.ws.url).toBe("ws://example.com/ws");
    expect(t.ws.headers).toEqual({});
    expect(t.ws.ignoreSSL).toBe(false);
    expect(t.ws.maxMessageBytes).toBe(4096);
    expect(t.ws.receiveTimeout).toBe(5000);
    expect(t.ws.send).toBeUndefined();
    expect(t.ws.subprotocols).toEqual([]);
    expect(t.expect).toEqual({ connected: true });
  });

  test("解析带 send 的 ws 配置", async () => {
    const configPath = join(tempDir, "ws-send.yaml");
    await writeFile(
      configPath,
      `targets:
  - id: "ws-echo"
    name: "WS Echo 检查"
    type: ws
    ws:
      url: "wss://api.example.com/ws"
      headers:
        Authorization: "Bearer token"
      subprotocols:
        - "json"
      ignoreSSL: true
      send: "ping"
      receiveTimeout: 3000
      maxMessageBytes: "8KB"
    expect:
      message:
        - contains: "pong"
      durationMs:
        lte: 5000
`,
    );

    const config = await loadConfig(configPath);
    expect(config.targets).toHaveLength(1);
    const t = config.targets[0]! as ResolvedWsTarget;
    expect(t.type).toBe("ws");
    expect(t.ws.url).toBe("wss://api.example.com/ws");
    expect(t.ws.headers).toEqual({ Authorization: "Bearer token" });
    expect(t.ws.ignoreSSL).toBe(true);
    expect(t.ws.maxMessageBytes).toBe(8192);
    expect(t.ws.receiveTimeout).toBe(3000);
    expect(t.ws.send).toBe("ping");
    expect(t.ws.subprotocols).toEqual(["json"]);
    expect(t.expect?.connected).toBe(true);
    expect(t.expect?.message).toBeDefined();
    expect(t.expect?.durationMs).toEqual({ lte: 5000 });
  });

  test("ws 缺少 url 抛出错误", async () => {
    const configPath = join(tempDir, "ws-no-url.yaml");
    await writeFile(
      configPath,
      `targets:
  - id: "t"
    type: ws
    ws: {}
`,
    );
    let error: unknown;
    try {
      await loadConfig(configPath);
    } catch (caught) {
      error = caught;
    }
    expect(error).toBeInstanceOf(Error);
    expect((error as Error).message).toContain("ws.url");
  });

  test("ws url 非 ws/wss 协议抛出错误", async () => {
    const configPath = join(tempDir, "ws-bad-url.yaml");
    await writeFile(
      configPath,
      `targets:
  - id: "t"
    type: ws
    ws:
      url: "http://example.com"
`,
    );
    let error: unknown;
    try {
      await loadConfig(configPath);
    } catch (caught) {
      error = caught;
    }
    expect(error).toBeInstanceOf(Error);
    expect((error as Error).message).toContain("ws:// 或 wss://");
  });

  test("ws expect.message 未配置 send 抛出错误", async () => {
    const configPath = join(tempDir, "ws-no-send.yaml");
    await writeFile(
      configPath,
      `targets:
  - id: "t"
    type: ws
    ws:
      url: "ws://example.com"
    expect:
      message:
        - contains: "pong"
`,
    );
    let error: unknown;
    try {
      await loadConfig(configPath);
    } catch (caught) {
      error = caught;
    }
    expect(error).toBeInstanceOf(Error);
    expect((error as Error).message).toContain("send");
  });
});
