import {
  isAdministrationRole,
  isAdministrationAdmin,
  isSuper,
  User,
  UserNotNull,
  isAdministration,
  isEntrepriseOrBureauDetudeRole,
  isEntrepriseOrBureauDEtude,
  isDefautRole,
  isSuperRole,
  isRole,
} from 'camino-common/src/roles'
import { canEditPermission, getAssignableRoles } from 'camino-common/src/permissions/utilisateurs'
import { equalStringArrays } from '../../tools/index'
import { isAdministrationId } from 'camino-common/src/static/administrations'
import { UtilisateurToEdit } from 'camino-common/src/utilisateur'
import { CaminoError } from 'camino-common/src/zod-tools'
import { Effect, Option } from 'effect'
import { isNotNullNorUndefined } from 'camino-common/src/typescript-tools'

const userIsCorrect = (utilisateur: UtilisateurToEdit): boolean => {
  if (!isRole(utilisateur.role)) {
    return false
  }
  if ((isSuperRole(utilisateur.role) || isDefautRole(utilisateur.role)) && utilisateur.administrationId === null && utilisateur.entrepriseIds.length === 0) {
    return true
  }

  if (isAdministrationRole(utilisateur.role) && isAdministrationId(utilisateur.administrationId) && utilisateur.entrepriseIds.length === 0) {
    return true
  }
  if (isEntrepriseOrBureauDetudeRole(utilisateur.role) && utilisateur.administrationId === null && utilisateur.entrepriseIds.length > 0) {
    return true
  }

  return false
}

const utilisateurIncorrect = 'utilisateur incorrect' as const
const utilisateurNonExistant = "l'utilisateur n'existe pas" as const
const droitsInsuffisants = 'droits insuffisants' as const
const impossibleDeModifierSonRole = 'impossible de modifier son propre rôle' as const
const impossibleDeModifierLesRoles = 'droits insuffisants pour modifier les rôles' as const
const droitsInsuffisantsPourModifierAdministration = 'droits insuffisants pour modifier les administrations' as const
const droitsInsuffisantPourModifierEntreprises = 'droits insuffisants pour modifier les entreprises' as const
export type UtilisateurUpdationValidateErrors =
  | typeof utilisateurIncorrect
  | typeof utilisateurNonExistant
  | typeof droitsInsuffisants
  | typeof impossibleDeModifierLesRoles
  | typeof droitsInsuffisantsPourModifierAdministration
  | typeof impossibleDeModifierSonRole
  | typeof droitsInsuffisantPourModifierEntreprises
export const utilisateurUpdationValidate = (user: UserNotNull, newUtilisateur: UtilisateurToEdit, utilisateurOld: User): Effect.Effect<void, CaminoError<UtilisateurUpdationValidateErrors>> => {
  return Effect.Do.pipe(
    Effect.map(() => utilisateurOld),
    Effect.filterOrFail(
      () => userIsCorrect(newUtilisateur),
      () => ({ message: utilisateurIncorrect })
    ),
    Effect.filterOrFail(
      (oldUser): oldUser is UserNotNull => isNotNullNorUndefined(oldUser),
      () => ({ message: utilisateurNonExistant })
    ),
    Effect.filterOrFail(
      oldUser => canEditPermission(user, oldUser) && canEditPermission(user, newUtilisateur as unknown as UserNotNull),
      () => ({ message: droitsInsuffisants })
    ),
    Effect.tap(oldUser => {
      if (newUtilisateur.role !== oldUser.role) {
        return Effect.Do.pipe(
          Effect.filterOrFail(
            () => user.id !== newUtilisateur.id,
            () => ({ message: impossibleDeModifierSonRole })
          ),
          Effect.filterOrFail(
            () => getAssignableRoles(user).includes(newUtilisateur.role),
            () => ({ message: impossibleDeModifierLesRoles })
          )
        )
      }
      return Effect.succeed(oldUser)
    }),
    Effect.tap(oldUser => {
      if (!isSuper(user)) {
        return Effect.Do.pipe(
          Effect.filterOrFail(
            () => !isAdministration(oldUser) || newUtilisateur.administrationId === oldUser.administrationId,
            () => ({ message: droitsInsuffisantsPourModifierAdministration })
          ),
          Effect.filterOrFail(
            () => isAdministrationAdmin(user) || (isEntrepriseOrBureauDEtude(utilisateurOld) && equalStringArrays(utilisateurOld.entrepriseIds.toSorted(), newUtilisateur.entrepriseIds.toSorted())),
            () => ({ message: droitsInsuffisantPourModifierEntreprises })
          )
        )
      }
      return Effect.succeed(Option.none)
    })
  )
}
