import { Type } from "@sinclair/typebox";

import type { CheckerSchemas } from "../types";

import {
  createAuthoringContentExpectationsSchema,
  createAuthoringFieldSchema,
  createAuthoringKeyedExpectationsSchema,
  createAuthoringStringMapSchema,
  createAuthoringValueExpectationSchema,
  createNormalizedContentExpectationsSchema,
  createNormalizedKeyedExpectationsSchema,
  createNormalizedValueExpectationSchema,
  sizeSchema,
  stringMapSchema,
} from "../../schema/fragments";

export const wsCheckerSchemas: CheckerSchemas = {
  authoring: {
    config: createWsConfigSchema("authoring"),
    expect: createWsExpectSchema("authoring"),
  },
  normalized: {
    config: createWsConfigSchema("normalized"),
    expect: createWsExpectSchema("normalized"),
  },
};

function createWsConfigSchema(kind: "authoring" | "normalized") {
  const bool = Type.Boolean();
  const timeout = Type.Number({ minimum: 0 });
  return Type.Object(
    {
      headers: Type.Optional(kind === "authoring" ? createAuthoringStringMapSchema() : stringMapSchema),
      ignoreSSL: Type.Optional(kind === "authoring" ? createAuthoringFieldSchema(bool) : bool),
      maxMessageBytes: Type.Optional(sizeSchema),
      receiveTimeout: Type.Optional(kind === "authoring" ? createAuthoringFieldSchema(timeout) : timeout),
      send: Type.Optional(Type.String()),
      subprotocols: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
      url: Type.String({ minLength: 1 }),
    },
    { additionalProperties: false },
  );
}

function createWsExpectSchema(kind: "authoring" | "normalized") {
  const connected = Type.Boolean();
  return Type.Object(
    {
      connected: Type.Optional(kind === "authoring" ? createAuthoringFieldSchema(connected) : connected),
      connectTimeMs: Type.Optional(
        kind === "authoring" ? createAuthoringValueExpectationSchema() : createNormalizedValueExpectationSchema(),
      ),
      durationMs: Type.Optional(
        kind === "authoring" ? createAuthoringValueExpectationSchema() : createNormalizedValueExpectationSchema(),
      ),
      handshakeHeaders: Type.Optional(
        kind === "authoring" ? createAuthoringKeyedExpectationsSchema() : createNormalizedKeyedExpectationsSchema(),
      ),
      message: Type.Optional(
        kind === "authoring" ? createAuthoringContentExpectationsSchema() : createNormalizedContentExpectationsSchema(),
      ),
    },
    { additionalProperties: false },
  );
}
