import type { CreateOperation, OptionalKeys, RequiredKeys } from '@prisma-extensions/core'
import type { Prisma } from '@prisma/client'

export type ArgReturnType<T> = T extends () => infer R ? R : T

export type ExtractData<Model, Operation extends CreateOperation = 'create'> = Prisma.Args<
  Model,
  Operation
>['data']

export type TransformKeys<
  Model,
  Data extends Prisma.Args<Model, Operation>['data'],
  Operation extends CreateOperation = 'create',
> = {
  [Key in keyof Pick<Data, RequiredKeys<Data>>]: Data[Key] | (() => Data[Key])
} & {
  [Key in keyof Pick<Data, OptionalKeys<Data>>]?: Data[Key] | (() => Data[Key])
}

export type DefaultData<Model, Args> = Prisma.Exact<Args, TransformKeys<Model, ExtractData<Model>>>

export interface FactoryBuilder<
  Model,
  Data = ExtractData<Model>,
  Input = Partial<TransformKeys<Model, Data>>,
> {
  attributes: (data?: Input) => Data
  create: (data?: Input) => Promise<Prisma.Result<Model, Data, 'create'>>
}
