import { type TransferListItem } from "worker_threads";
import { z } from "zod";
import { UNUSED } from "./common";

export namespace MsgProtocol {
  const QueryDataSchema = z.object({ type: z.literal("Query"), args: z.any() })
  const ResultDataSchema = z.object({ type: z.literal("Result"), result: z.any() })
  const ErrorDataSchema = z.object({ type: z.literal("Error"), error: z.string() })

  const MessageSchema = z.object({
    command: z.string(),
    data: z.discriminatedUnion("type", [QueryDataSchema, ResultDataSchema, ErrorDataSchema]),
    dest: z.string(),
    src: z.string(),
  })
  const MessageQuerySchema = z.object({
    command: z.string(),
    data: QueryDataSchema,
    dest: z.string(),
    src: z.string(),
  })
  const MessageResultSchema = z.object({
    command: z.string(),
    data: ResultDataSchema,
    dest: z.string(),
    src: z.string(),
  })
  const MessageErrorSchema = z.object({
    command: z.string(),
    data: ErrorDataSchema,
    dest: z.string(),
    src: z.string(),
  })
  const MessageHandlerSchema = z.function()
    .args(z.union([MessageResultSchema, MessageErrorSchema]))
    .returns(z.void())

  export type Message = z.infer<typeof MessageSchema>
  export type MessageQuery = z.infer<typeof MessageQuerySchema>
  export type MessageResult = z.infer<typeof MessageResultSchema>
  export type MessageError = z.infer<typeof MessageErrorSchema>
  export type MessageHandler = z.infer<typeof MessageHandlerSchema>

  export function isMessage(obj: any): obj is Message {
    return MessageSchema.safeParse(obj).success
  }
  export function isMessageQuery(obj: any): obj is MessageQuery {
    return MessageQuerySchema.safeParse(obj).success
  }
  export function isMessageResult(obj: any): obj is MessageResult {
    return MessageResultSchema.safeParse(obj).success
  }
  export function isMessageError(obj: any): obj is MessageError {
    return MessageErrorSchema.safeParse(obj).success
  }

  export function genMessageResult(result: any, srcMsg: MessageQuery): MessageResult {
    return {
      command: srcMsg.command,
      dest: srcMsg.src,
      src: srcMsg.dest,
      data: {
        type: "Result",
        result: result
      }
    } as MessageResult
  }
  export function genMessageError(error: string, srcMsg: MessageQuery): MessageError {
    return {
      command: srcMsg.command,
      dest: srcMsg.src,
      src: srcMsg.dest,
      data: {
        type: "Error",
        error: error
      }
    } as MessageError
  }
}