import { z } from "zod";

import { type Datum } from "./datum.svelte.ts";

type Assert<_T extends true> = void;

export const RFC_3339_S = "yyyy-MM-dd'T'HH:mm:ssXXX";

export const all_presentation_tags = [
  "Dropdown",
  "Numeric",
  "Text",
  "Timestamp",
  "Uuid",
] as const;

// Type checking to ensure that all valid enum tags are included.
type _PresentationTagsAssertionA = Assert<
  Presentation["t"] extends (typeof all_presentation_tags)[number] ? true
    : false
>;
type _PresentationTagsAssertionB = Assert<
  (typeof all_presentation_tags)[number] extends Presentation["t"] ? true
    : false
>;

export const all_text_input_modes = [
  "SingleLine",
  "MultiLine",
] as const;

// Type checking to ensure that all valid enum tags are included.
type _TextInputModesAssertionA = Assert<
  TextInputMode["t"] extends (typeof all_text_input_modes)[number] ? true
    : false
>;
type _TextInputModesAssertionB = Assert<
  (typeof all_text_input_modes)[number] extends TextInputMode["t"] ? true
    : false
>;

const presentation_numeric_schema = z.object({
  t: z.literal("Numeric"),
  c: z.object({}),
});

const text_input_mode_schema = z.union([
  z.object({
    t: z.literal("SingleLine"),
    c: z.object({}),
  }),
  z.object({
    t: z.literal("MultiLine"),
    c: z.object({}),
  }),
]);

export type TextInputMode = z.infer<typeof text_input_mode_schema>;

const dropdown_option_schema = z.object({
  color: z.string(),
  value: z.string(),
});

export type DropdownOption = z.infer<typeof dropdown_option_schema>;

const presentation_dropdown_schema = z.object({
  t: z.literal("Dropdown"),
  c: z.object({
    allow_custom: z.boolean(),
    options: z.array(dropdown_option_schema),
  }),
});

export type PresentationDropdown = z.infer<typeof presentation_dropdown_schema>;

const presentation_text_schema = z.object({
  t: z.literal("Text"),
  c: z.object({
    input_mode: text_input_mode_schema,
  }),
});

export type PresentationText = z.infer<typeof presentation_text_schema>;

const presentation_timestamp_schema = z.object({
  t: z.literal("Timestamp"),
  c: z.object({
    format: z.string(),
  }),
});

export type PresentationTimestamp = z.infer<
  typeof presentation_timestamp_schema
>;

const presentation_uuid_schema = z.object({
  t: z.literal("Uuid"),
  c: z.unknown(),
});

export type PresentationUuid = z.infer<typeof presentation_uuid_schema>;

export const presentation_schema = z.union([
  presentation_dropdown_schema,
  presentation_numeric_schema,
  presentation_text_schema,
  presentation_timestamp_schema,
  presentation_uuid_schema,
]);

export type Presentation = z.infer<typeof presentation_schema>;

export function get_empty_datum_for(presentation: Presentation): Datum {
  if (presentation.t === "Dropdown") {
    return { t: "Text", c: undefined };
  }
  if (presentation.t === "Numeric") {
    return { t: "Numeric", c: undefined };
  }
  if (presentation.t === "Text") {
    return { t: "Text", c: undefined };
  }
  if (presentation.t === "Timestamp") {
    return { t: "Timestamp", c: undefined };
  }
  if (presentation.t === "Uuid") {
    return { t: "Uuid", c: undefined };
  }
  type _ = Assert<typeof presentation extends never ? true : false>;
  throw new Error("this should be unreachable");
}
