import { Awaitable, LiteralString, UnionToIntersection } from "../types/helper.mjs";
import { BetterAuthOptions } from "../types/init-options.mjs";
import { StandardSchemaV1 } from "@standard-schema/spec";

//#region src/db/type.d.ts
type BaseModelNames = "user" | "account" | "session" | "verification";
type ModelNames<T extends string = LiteralString> = BaseModelNames | T | "rate-limit";
type InferDBValueType<T extends DBFieldType> = T extends "string" ? string : T extends "number" ? number : T extends "boolean" ? boolean : T extends "date" ? Date : T extends "json" ? Record<string, any> : T extends `${infer U}[]` ? U extends "string" ? string[] : number[] : T extends Array<any> ? T[number] : never;
type InferDBFieldOutput<T extends DBFieldAttribute> = T["returned"] extends false ? never : T["required"] extends false ? InferDBValueType<T["type"]> | undefined | null : InferDBValueType<T["type"]>;
type InferDBFieldInput<T extends DBFieldAttribute> = InferDBValueType<T["type"]>;
type InferDBFieldsInput<Field> = Field extends Record<infer Key, DBFieldAttribute> ? { [key in Key as Field[key]["required"] extends false ? never : Field[key]["defaultValue"] extends string | number | boolean | Date ? never : Field[key]["input"] extends false ? never : key]: InferDBFieldInput<Field[key]> } & { [key in Key as Field[key]["input"] extends false ? never : key]?: InferDBFieldInput<Field[key]> | undefined | null } : {};
type InferDBFieldsOutput<Fields extends Record<string, DBFieldAttribute>> = Fields extends Record<infer Key, DBFieldAttribute> ? { [key in Key as Fields[key]["returned"] extends false ? never : Fields[key]["required"] extends false ? Fields[key]["defaultValue"] extends boolean | string | number | Date ? key : never : key]: InferDBFieldOutput<Fields[key]> } & { [key in Key as Fields[key]["returned"] extends false ? never : Fields[key]["required"] extends false ? Fields[key]["defaultValue"] extends boolean | string | number | Date ? never : key : never]?: InferDBFieldOutput<Fields[key]> | null } : never;
type InferDBFieldsFromOptionsInput<DBOptions extends BetterAuthOptions["session"] | BetterAuthOptions["user"] | BetterAuthOptions["verification"] | BetterAuthOptions["account"] | BetterAuthOptions["rateLimit"]> = DBOptions extends {
  additionalFields: Record<string, DBFieldAttribute>;
} ? InferDBFieldsInput<DBOptions["additionalFields"]> : {};
type InferDBFieldsFromOptions<DBOptions extends BetterAuthOptions["session"] | BetterAuthOptions["user"] | BetterAuthOptions["verification"] | BetterAuthOptions["account"] | BetterAuthOptions["rateLimit"]> = DBOptions extends {
  additionalFields: Record<string, DBFieldAttribute>;
} ? InferDBFieldsOutput<DBOptions["additionalFields"]> : {};
type InferDBFieldsFromPluginsInput<ModelName extends string, Plugins extends unknown[] | undefined> = Plugins extends [] ? {} : Plugins extends [infer P, ...infer Rest] ? P extends {
  schema: { [key in ModelName]: {
    fields: infer Fields;
  } };
} ? Fields extends Record<string, DBFieldAttribute> ? UnionToIntersection<InferDBFieldsInput<Fields> & InferDBFieldsFromPluginsInput<ModelName, Rest>> : InferDBFieldsFromPluginsInput<ModelName, Rest> : InferDBFieldsFromPluginsInput<ModelName, Rest> : {};
type InferDBFieldsFromPlugins<ModelName extends string, Plugins extends unknown[] | undefined> = Plugins extends [] ? {} : Plugins extends [infer P, ...infer Rest] ? P extends {
  schema: { [key in ModelName]: {
    fields: infer Fields;
  } };
} ? Fields extends Record<string, DBFieldAttribute> ? UnionToIntersection<InferDBFieldsOutput<Fields> & InferDBFieldsFromPlugins<ModelName, Rest>> : InferDBFieldsFromPlugins<ModelName, Rest> : InferDBFieldsFromPlugins<ModelName, Rest> : {};
type DBFieldType = "string" | "number" | "boolean" | "date" | "json" | `${"string" | "number"}[]` | Array<LiteralString>;
type DBPrimitive = string | number | boolean | Date | null | undefined | string[] | number[] | (Record<string, unknown> | unknown[]);
type DBFieldAttributeConfig = {
  /**
   * If the field should be required on a new record.
   * @default true
   */
  required?: boolean | undefined;
  /**
   * If the value should be returned on a response body.
   * @default true
   */
  returned?: boolean | undefined;
  /**
   * If a value should be provided when creating a new record.
   * @default true
   */
  input?: boolean | undefined;
  /**
   * Default value for the field
   *
   * Note: This will not create a default value on the database level. It will only
   * be used when creating a new record.
   */
  defaultValue?: (DBPrimitive | (() => DBPrimitive)) | undefined;
  /**
   * Update value for the field
   *
   * Note: This will create an onUpdate trigger on the database level for supported adapters.
   * It will be called when updating a record.
   */
  onUpdate?: (() => DBPrimitive) | undefined;
  /**
   * transform the value before storing it.
   */
  transform?: {
    input?: (value: DBPrimitive) => Awaitable<DBPrimitive>;
    output?: (value: DBPrimitive) => Awaitable<DBPrimitive>;
  } | undefined;
  /**
   * Reference to another model.
   */
  references?: {
    /**
     * The model to reference.
     */
    model: string;
    /**
     * The field on the referenced model.
     */
    field: string;
    /**
     * The action to perform when the reference is deleted.
     * @default "cascade"
     */
    onDelete?: "no action" | "restrict" | "cascade" | "set null" | "set default";
  } | undefined;
  unique?: boolean | undefined;
  /**
   * If the field should be a bigint on the database instead of integer.
   */
  bigint?: boolean | undefined;
  /**
   * A zod schema to validate the value.
   */
  validator?: {
    input?: StandardSchemaV1;
    output?: StandardSchemaV1;
  } | undefined;
  /**
   * The name of the field on the database.
   */
  fieldName?: string | undefined;
  /**
   * If the field should be sortable.
   *
   * applicable only for `text` type.
   * It's useful to mark fields varchar instead of text.
   */
  sortable?: boolean | undefined;
  /**
   * If the field should be indexed.
   * @default false
   */
  index?: boolean | undefined;
};
type DBFieldAttribute<T extends DBFieldType = DBFieldType> = {
  type: T;
} & DBFieldAttributeConfig;
type BetterAuthDBSchema = Record<string, {
  /**
   * The name of the table in the database
   */
  modelName: string;
  /**
   * The fields of the table
   */
  fields: Record<string, DBFieldAttribute>;
  /**
   * Whether to disable migrations for this table
   * @default false
   */
  disableMigrations?: boolean | undefined;
  /**
   * The order of the table
   */
  order?: number | undefined;
}>;
interface SecondaryStorage {
  /**
   *
   * @param key - Key to get
   * @returns - Value of the key
   */
  get: (key: string) => Awaitable<unknown>;
  set: (
  /**
   * Key to store
   */

  key: string,
  /**
   * Value to store
   */

  value: string,
  /**
   * Time to live in seconds
   */

  ttl?: number | undefined) => Awaitable<void | null | unknown>;
  /**
   *
   * @param key - Key to delete
   */
  delete: (key: string) => Awaitable<void | null | string>;
}
//#endregion
export { BaseModelNames, BetterAuthDBSchema, DBFieldAttribute, DBFieldAttributeConfig, DBFieldType, DBPrimitive, InferDBFieldInput, InferDBFieldOutput, InferDBFieldsFromOptions, InferDBFieldsFromOptionsInput, InferDBFieldsFromPlugins, InferDBFieldsFromPluginsInput, InferDBFieldsInput, InferDBFieldsOutput, InferDBValueType, ModelNames, SecondaryStorage };