import { Request as JWTRequest } from 'express-jwt'
import { HTTP_STATUS } from 'camino-common/src/http'

import { CustomResponse } from './express-type'
import { AdminUserNotNull, User } from 'camino-common/src/roles'
import { Pool } from 'pg'
import { administrationIdValidator } from 'camino-common/src/static/administrations'
import { canReadAdministrations } from 'camino-common/src/permissions/administrations'
import { deleteAdministrationActiviteTypeEmail, getActiviteTypeEmailsByAdministrationId, getUtilisateursByAdministrationId, insertAdministrationActiviteTypeEmail } from './administrations.queries'
import { AdministrationActiviteTypeEmail } from 'camino-common/src/administrations'
import { CaminoApiError } from '../../types'
import { EffectDbQueryAndValidateErrors } from '../../pg-database'
import { Effect, Match } from 'effect'
import { RestNewPostCall } from '../../server/rest'

export const getAdministrationUtilisateurs =
  (pool: Pool) =>
  async (req: JWTRequest<User>, res: CustomResponse<AdminUserNotNull[]>): Promise<void> => {
    const user = req.auth

    const parsed = administrationIdValidator.safeParse(req.params.administrationId)

    if (!parsed.success) {
      console.warn(`l'administrationId est obligatoire`)
      res.sendStatus(HTTP_STATUS.FORBIDDEN)
    } else if (!canReadAdministrations(user)) {
      res.sendStatus(HTTP_STATUS.FORBIDDEN)
    } else {
      try {
        res.json(await getUtilisateursByAdministrationId(pool, parsed.data))
      } catch (e) {
        console.error(e)

        res.sendStatus(HTTP_STATUS.INTERNAL_SERVER_ERROR)
      }
    }
  }

export const getAdministrationActiviteTypeEmails =
  (pool: Pool) =>
  async (req: JWTRequest<User>, res: CustomResponse<AdministrationActiviteTypeEmail[]>): Promise<void> => {
    const user = req.auth

    const parsed = administrationIdValidator.safeParse(req.params.administrationId)

    if (!parsed.success) {
      console.warn(`l'administrationId est obligatoire`)
      res.sendStatus(HTTP_STATUS.FORBIDDEN)
    } else if (!canReadAdministrations(user)) {
      res.sendStatus(HTTP_STATUS.FORBIDDEN)
    } else {
      try {
        res.json(await getActiviteTypeEmailsByAdministrationId(pool, parsed.data))
      } catch (e) {
        console.error(e)

        res.sendStatus(HTTP_STATUS.INTERNAL_SERVER_ERROR)
      }
    }
  }

export const addAdministrationActiviteTypeEmails: RestNewPostCall<'/rest/administrations/:administrationId/activiteTypeEmails'> = (
  rootPipe
): Effect.Effect<boolean, CaminoApiError<'Accès interdit' | EffectDbQueryAndValidateErrors>> => {
  return rootPipe.pipe(
    Effect.filterOrFail(
      ({ user }) => canReadAdministrations(user),
      () => ({ message: 'Accès interdit' as const })
    ),
    Effect.flatMap(({ pool, params, body }) => insertAdministrationActiviteTypeEmail(pool, params.administrationId, body)),
    Effect.mapError(caminoError =>
      Match.value(caminoError.message).pipe(
        Match.when('Accès interdit', () => ({ ...caminoError, status: HTTP_STATUS.FORBIDDEN })),
        Match.whenOr("Impossible d'exécuter la requête dans la base de données", 'Les données en base ne correspondent pas à ce qui est attendu', () => ({
          ...caminoError,
          status: HTTP_STATUS.INTERNAL_SERVER_ERROR,
        })),
        Match.exhaustive
      )
    )
  )
}

export const deleteAdministrationActiviteTypeEmails: RestNewPostCall<'/rest/administrations/:administrationId/activiteTypeEmails/delete'> = (
  rootPipe
): Effect.Effect<boolean, CaminoApiError<'Accès interdit' | EffectDbQueryAndValidateErrors>> => {
  return rootPipe.pipe(
    Effect.filterOrFail(
      ({ user }) => canReadAdministrations(user),
      () => ({ message: 'Accès interdit' as const })
    ),
    Effect.flatMap(({ pool, params, body }) => deleteAdministrationActiviteTypeEmail(pool, params.administrationId, body)),
    Effect.mapError(caminoError =>
      Match.value(caminoError.message).pipe(
        Match.when('Accès interdit', () => ({ ...caminoError, status: HTTP_STATUS.FORBIDDEN })),
        Match.whenOr("Impossible d'exécuter la requête dans la base de données", 'Les données en base ne correspondent pas à ce qui est attendu', () => ({
          ...caminoError,
          status: HTTP_STATUS.INTERNAL_SERVER_ERROR,
        })),
        Match.exhaustive
      )
    )
  )
}
