import { isEntrepriseOrBureauDetudeRole, Role, User, UserNotNull, isAdministration, isSuper, isEntrepriseOrBureauDEtude, isAdministrationRole, UtilisateurId } from 'camino-common/src/roles'
import { computed, defineComponent, ref } from 'vue'
import { AdministrationId, Administrations, sortedAdministrations } from 'camino-common/src/static/administrations'
import { Entreprise, EntrepriseId } from 'camino-common/src/entreprise'
import { UtilisateurToEdit } from 'camino-common/src/utilisateur'
import { canEditPermission, getAssignableRoles } from 'camino-common/src/permissions/utilisateurs'
import { UtilisateurApiClient } from './utilisateur-api-client'
import { TypeAheadSmartMultiple, Element } from '../_ui/typeahead-smart-multiple'
import { isNotNullNorUndefined, isNotNullNorUndefinedNorEmpty, map } from 'camino-common/src/typescript-tools'
import { capitalize } from 'camino-common/src/strings'
import { DsfrSelect } from '../_ui/dsfr-select'
import { DsfrButton, DsfrButtonIcon } from '../_ui/dsfr-button'
import { LabelWithValue } from '../_ui/label-with-value'
import { DsfrTag } from '../_ui/tag'
import { CaminoError } from 'camino-common/src/zod-tools'
import { AsyncData } from '@/api/client-rest'
import { LoadingElement } from '../_ui/functional-loader'
import { fr } from '@codegouvfr/react-dsfr'

interface Props {
  user: User
  utilisateur: UserNotNull
  apiClient: Pick<UtilisateurApiClient, 'updateUtilisateur'>
  entreprises: Entreprise[]
}

export const PermissionDisplay = defineComponent<Props>(props => {
  const mode = ref<'read' | 'edit'>('read')

  const updateUtilisateur = async (utilisateur: UtilisateurToEdit) => {
    const value = await props.apiClient.updateUtilisateur(utilisateur)
    if ('message' in value) {
      return value
    }
    mode.value = 'read'
    return value
  }

  return () => (
    <>
      {mode.value === 'read' ? (
        <>
          <LabelWithValue
            title="Rôles"
            item={
              <div style={{ display: 'flex', flexDirection: 'row', alignContent: 'center', alignItems: 'center' }}>
                <DsfrTag ariaLabel={capitalize(props.utilisateur.role)} />
                {canEditPermission(props.user, props.utilisateur) ? (
                  <DsfrButtonIcon buttonType="tertiary-no-outline" title="Modifie les permissions" onClick={() => (mode.value = 'edit')} icon="fr-icon-pencil-line" />
                ) : null}
              </div>
            }
          />

          {isEntrepriseOrBureauDEtude(props.utilisateur) && isNotNullNorUndefinedNorEmpty(props.utilisateur.entrepriseIds) ? (
            <LabelWithValue
              title={`Entreprise${props.utilisateur.entrepriseIds.length > 0 ? 's' : ''}`}
              item={
                <ul class={fr.cx('fr-tags-group')}>
                  {isEntrepriseOrBureauDEtude(props.utilisateur) &&
                    props.utilisateur.entrepriseIds.map(entrepriseId => {
                      const e = props.entreprises.find(({ id }) => id === entrepriseId)

                      return e ? (
                        <li key={e.id}>
                          <DsfrTag ariaLabel={isNotNullNorUndefined(e.legal_siren) ? `${e.nom} (${e.legal_siren})` : e.nom} to={{ name: 'entreprise', params: { id: e.id } }} />
                        </li>
                      ) : null
                    })}
                </ul>
              }
            />
          ) : null}

          {isAdministration(props.utilisateur) ? (
            <LabelWithValue
              title="Administration"
              item={
                <DsfrTag
                  ariaLabel={`${Administrations[props.utilisateur.administrationId].abreviation}${
                    isNotNullNorUndefined(Administrations[props.utilisateur.administrationId].service) ? ` - ${Administrations[props.utilisateur.administrationId].service}` : ''
                  }`}
                  to={{ name: 'administration', params: { id: props.utilisateur.administrationId } }}
                />
              }
            />
          ) : null}
        </>
      ) : (
        <PermissionEdit cancelEdition={() => (mode.value = 'read')} user={props.user} utilisateur={props.utilisateur} entreprises={props.entreprises} updateUtilisateur={updateUtilisateur} />
      )}
    </>
  )
})

type PermissionEditProps = {
  user: User
  utilisateur: UserNotNull
  entreprises: Entreprise[]
  updateUtilisateur: (utilisateur: UtilisateurToEdit) => Promise<{ id: UtilisateurId } | CaminoError<string>>
  cancelEdition: () => void
}

const PermissionEdit = defineComponent<PermissionEditProps>(props => {
  const asyncData = ref<AsyncData<{ id: UtilisateurId }>>({ status: 'LOADED', value: { id: props.utilisateur.id } })
  const updatingUtilisateur = ref<UtilisateurToEdit>({
    id: props.utilisateur.id,
    role: props.utilisateur.role,
    entrepriseIds: isEntrepriseOrBureauDEtude(props.utilisateur) ? props.utilisateur.entrepriseIds : [],
    administrationId: isAdministration(props.utilisateur) ? props.utilisateur.administrationId : null,
  })

  const assignableRoles = getAssignableRoles(props.user)
  const onSelectEntreprises = (elements: Element<EntrepriseId>[]) => {
    const entrs = elements.map(({ id }) => id)
    updatingUtilisateur.value.entrepriseIds.splice(0, updatingUtilisateur.value.entrepriseIds.length, ...entrs)
  }

  const complete = computed(() => {
    if (isEntrepriseOrBureauDetudeRole(updatingUtilisateur.value.role) && !updatingUtilisateur.value.entrepriseIds?.length) {
      return false
    }

    if (isAdministrationRole(updatingUtilisateur.value.role) && !updatingUtilisateur.value.administrationId) {
      return false
    }

    return true
  })

  const selectAdministration = (e: AdministrationId | null) => {
    if (isNotNullNorUndefined(e)) {
      updatingUtilisateur.value.administrationId = e
    }
  }

  const save = async () => {
    if (complete.value) {
      asyncData.value = { status: 'LOADING' }
      if (!isAdministrationRole(updatingUtilisateur.value.role)) {
        updatingUtilisateur.value.administrationId = null
      }

      if (!isEntrepriseOrBureauDetudeRole(updatingUtilisateur.value.role)) {
        updatingUtilisateur.value.entrepriseIds = []
      }

      const result = await props.updateUtilisateur(updatingUtilisateur.value)
      if ('message' in result) {
        asyncData.value = { status: 'NEW_ERROR', error: result }
      } else {
        asyncData.value = { status: 'LOADED', value: result }
      }
    }
  }

  const roleToggle = (role: Role) => {
    updatingUtilisateur.value.role = role
    if (isAdministration(props.user) && isAdministrationRole(updatingUtilisateur.value.role)) {
      updatingUtilisateur.value.administrationId = props.user.administrationId
    }
  }

  return () => (
    <>
      {!!props.user && props.user.id !== updatingUtilisateur.value.id && assignableRoles.length > 0 ? (
        <>
          <LabelWithValue
            title="Rôles"
            item={
              <ul class={fr.cx('fr-tags-group')}>
                {assignableRoles.map(role => (
                  <li>
                    <DsfrButton class={fr.cx('fr-tag')} onClick={() => roleToggle(role)} aria-pressed={updatingUtilisateur.value.role === role} title={capitalize(role)} />
                  </li>
                ))}
              </ul>
            }
          />

          {isEntrepriseOrBureauDetudeRole(updatingUtilisateur.value.role) ? (
            <LabelWithValue
              title="Entreprises"
              item={
                <TypeAheadSmartMultiple
                  id="entreprises-role"
                  filter={{
                    name: 'Entreprises',
                    value: updatingUtilisateur.value.entrepriseIds,
                    elements: props.entreprises,
                    lazy: false,
                  }}
                  onSelectItems={elements => onSelectEntreprises(elements)}
                />
              }
            />
          ) : null}

          {isSuper(props.user) && isAdministrationRole(updatingUtilisateur.value.role) ? (
            <LabelWithValue
              title="Administration"
              item={
                <DsfrSelect
                  id="administration_utilisateur"
                  required={true}
                  items={map(sortedAdministrations, admin => ({ id: admin.id, label: admin.abreviation }))}
                  initialValue={updatingUtilisateur.value.administrationId}
                  legend={{ main: '' }}
                  valueChanged={selectAdministration}
                />
              }
            />
          ) : null}

          <LabelWithValue
            title=""
            item={
              <div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
                <DsfrButton title="Annuler" buttonType="secondary" onClick={props.cancelEdition} disabled={asyncData.value.status === 'LOADING'} />
                <DsfrButton title="Enregistrer" buttonType="primary" onClick={save} disabled={!complete.value || asyncData.value.status === 'LOADING'} />
                {asyncData.value.status !== 'LOADED' ? <LoadingElement data={asyncData.value} renderItem={_ => null} /> : null}
              </div>
            }
          />
        </>
      ) : null}
    </>
  )
})

// @ts-ignore waiting for https://github.com/vuejs/core/issues/7833
PermissionEdit.props = ['user', 'utilisateur', 'entreprises', 'updateUtilisateur', 'cancelEdition']

// @ts-ignore waiting for https://github.com/vuejs/core/issues/7833
PermissionDisplay.props = ['user', 'utilisateur', 'apiClient', 'entreprises']
