import { sql } from '@pgtyped/runtime'
import { DBNotFound, EffectDbQueryAndValidateErrors, Redefine, dbNotFoundError, effectDbQueryAndValidate } from '../../pg-database.js'
import { Pool } from 'pg'
import { Effect } from 'effect'
import { CaminoError } from 'camino-common/src/zod-tools.js'
import { logsMethodValidator, MutationId, mutationIdValidator } from 'camino-common/src/mutations.js'
import { IGetMutationDbQuery, IGetMutationsDbQuery } from './mutations.queries.types.js'
import { z } from 'zod'
import { utilisateurIdValidator } from 'camino-common/src/roles.js'

const mutationDbValidator = z.object({
  id: mutationIdValidator,
  datetime: z.date(),
  method: logsMethodValidator,
  path: z.string(),
  utilisateur_nom: z.string(),
  utilisateur_prenom: z.string(),
  utilisateur_id: utilisateurIdValidator,
  camino_path: z.string(),
  camino_variables: z.record(z.string(), z.string()),
})

type MutationDb = z.infer<typeof mutationDbValidator>

export const getMutations = (pool: Pool, email: string | undefined): Effect.Effect<MutationDb[], CaminoError<EffectDbQueryAndValidateErrors>> =>
  effectDbQueryAndValidate(getMutationsDb, { email: `%${email ?? ''}%` }, pool, mutationDbValidator)

const getMutationsDb = sql<Redefine<IGetMutationsDbQuery, { email: string | undefined }, MutationDb>>`
SELECT
  l.id,
  datetime,
  path,
  method,
  u.nom as utilisateur_nom,
  u.prenom as utilisateur_prenom,
  u.id as utilisateur_id,
  camino_path,
  camino_variables
FROM logs l
JOIN utilisateurs u ON u.id = l.utilisateur_id
WHERE ($email::TEXT = '%%' OR u.email LIKE $email)
ORDER BY datetime desc
`

export type GetMutationErrors = EffectDbQueryAndValidateErrors | DBNotFound

const getMutationDbValidator = mutationDbValidator.extend({ body: z.object({}).passthrough() })
type GetMutationDb = z.infer<typeof getMutationDbValidator>
export const getMutation = (pool: Pool, mutationId: MutationId): Effect.Effect<GetMutationDb, CaminoError<GetMutationErrors>> =>
  effectDbQueryAndValidate(getMutationDb, { mutationId }, pool, getMutationDbValidator).pipe(
    Effect.filterOrFail(
      result => result.length === 1,
      () => ({ message: dbNotFoundError })
    ),
    Effect.map(result => result[0])
  )

const getMutationDb = sql<Redefine<IGetMutationDbQuery, { mutationId: MutationId }, GetMutationDb>>`
SELECT
  l.id,
  datetime,
  path,
  method,
  body,
  u.nom as utilisateur_nom,
  u.prenom as utilisateur_prenom,
  u.id as utilisateur_id,
  camino_path,
  camino_variables
FROM logs l
JOIN utilisateurs u ON u.id = l.utilisateur_id
WHERE l.id = $mutationId!
`
