import * as _ from 'lodash'
import { AbilitiesType, AnyJson } from '~/types/interfaces'

const rolesByFunction: Array<string> = [
  'ROLE_SUPER_ADMIN',
  'ROLE_ADMIN',
  'ROLE_ADMIN_CORE',
  'ROLE_ADMINISTRATIF_MANAGER',
  'ROLE_ADMINISTRATIF_MANAGER_CORE',
  'ROLE_PEDAGOGICS_MANAGER',
  'ROLE_PEDAGOGICS_MANAGER_CORE',
  'ROLE_FINANCIAL_MANAGER',
  'ROLE_FINANCIAL_MANAGER_CORE',
  'ROLE_CA',
  'ROLE_CA_CORE',
  'ROLE_STUDENT',
  'ROLE_STUDENT_CORE',
  'ROLE_TEACHER',
  'ROLE_TEACHER_CORE',
  'ROLE_MEMBER',
  'ROLE_MEMBER_CORE',
  'ROLE_OTHER',
  'ROLE_OTHER_CORE'
]

const rolesToChange: Array<string> = [
  'ROLE_GENERAL_CONFIG',
  'ROLE_GENERAL_CONFIG_VIEW',
  'ROLE_TAGG_ADVANCED',
  'ROLE_TAGG_ADVANCED_VIEW',
  'ROLE_PEDAGOGICS_ADMINISTRATION',
  'ROLE_PEDAGOGICS_ADMINISTRATION_VIEW',
  'ROLE_PEDAGOGICS_SEIZURE',
  'ROLE_PEDAGOGICS_SEIZURE_VIEW',
  'ROLE_BILLINGS_ADMINISTRATION',
  'ROLE_BILLINGS_ADMINISTRATION_VIEW',
  'ROLE_BILLINGS_SEIZURE',
  'ROLE_BILLINGS_SEIZURE_VIEW',
  'ROLE_ONLINEREGISTRATION_ADMINISTRATION',
  'ROLE_ONLINEREGISTRATION_ADMINISTRATION_VIEW'
]

const actionMap: AnyJson = {
  '': 'manage',
  _VIEW: 'read'
}

/**
 * Classe permettant de mener des opérations sur les rôles
 */
class RoleUtils {
  /**
   * Teste si une personne possède un profil suivant ses rôles
   *
   * @param {string} profileName
   * @param {Array<string>} roles
   * @return {boolean}
   */
  isA (profileName: string, roles: Array<string>): boolean {
    profileName = profileName.toUpperCase()
    if (!profileName.match(/[A-Z_]+/)) {
      throw new Error('invalid role name')
    }
    return roles.includes('ROLE_' + profileName + '_CORE')
  }

  /**
   * Filtre les rôles afin d'en exclure les "Roles fonctions"
   *
   * @param {Array<string>} roles
   * @return {Array<string>}
   */
  filterFunctionRoles (roles: Array<string>): Array<string> {
    return roles.filter((role) => {
      return !rolesByFunction.includes(role)
    })
  }

  /**
   * Fix en attendant la migration complète, quelques rôles disposent d'underscore en trop, on corrige cela...
   *
   * @param {Array<string>} roles
   * @return {Array<string>}
   */
  transformUnderscoreToHyphenBeforeCompleteMigration (roles: Array<string>): Array<string> {
    const regex = /(ROLE_)([A-Z]*_[A-Z]*)([A-Z_]*)*/i
    let match
    roles = roles.map((role) => {
      if (rolesToChange.includes(role)) {
        if ((match = regex.exec(role)) !== null) {
          const role = match[1]
          const subject = match[2].replace('_', '-')
          const action = match[3]
          return role + subject + (action || '')
        }
      }
      return role
    })
    return roles
  }

  /**
   * On transforme les ROLES Symfony en Abilities
   *
   * @param {Array<string>} roles
   * @return {Array<AbilitiesType>}
   */
  transformRoleToAbilities (roles: Array<string>): [] | Array<AbilitiesType> {
    const abilities:Array<AbilitiesType> = []

    const regex = /(ROLE_)([A-Z-]*)([_A-Z]*)/i
    let match

    _.each(roles, (role) => {
      if ((match = regex.exec(role)) !== null) {
        const subject = match[2]
        const action = match[3]
        if(subject){
          abilities.push({
            action: actionMap[action],
            subject: subject.toLowerCase()
          })
        }
      }
    })

    return abilities
  }
}

export const $roleUtils = new RoleUtils()
