import {AnyJson, ApiResponse, HydraMetadata} from '~/types/interfaces'
import BaseDenormalizer from '~/services/serializer/denormalizer/baseDenormalizer'
import {DENORMALIZER_TYPE, METADATA_TYPE} from '~/types/enums'
import {parseInt} from "lodash";

/**
 * Classe permettant d'assurer la dénormalization d'un objet Hydra en JSON
 */
class Hydra extends BaseDenormalizer {
  static support (type: DENORMALIZER_TYPE): boolean {
    return type === DENORMALIZER_TYPE.HYDRA
  }

  /**
   * Parcourt une réponse Hydra pour retourner son équivalent en Json
   *
   * @param {AnyJson} hydraData
   * @return {AnyJson} réponse parsée
   */
  public static denormalize (hydraData: AnyJson): AnyJson {
    if (hydraData['hydra:member']) {
      hydraData.totalCount = hydraData['hydra:totalItems']
      return Hydra.parseCollection(hydraData)
    } else {
      return Hydra.parseItem(hydraData)
    }
  }

  private static parseItem (hydraData: AnyJson): ApiResponse {
    const itemResponse: ApiResponse = {
      data: hydraData,
      metadata: Hydra.definedMetadataForItem(hydraData)
    }
    return itemResponse
  }
    /**
   * Méthode de parsing appelé si on est dans un GET
   *
   * @param {AnyJson} hydraData
   */
  private static definedMetadataForItem (hydraData: AnyJson): AnyJson {
    const metadata:HydraMetadata = {}

    // if (hydraData['hydra:previous']) {
    //   const iriParts = hydraData['hydra:previous'].split('/')
    //   hydraData.previous = iriParts[iriParts.length - 1]
    // }
    // if (hydraData['hydra:next']) {
    //   const iriParts = hydraData['hydra:next'].split('/')
    //   hydraData.next = iriParts[iriParts.length - 1]
    // }
    // if (hydraData['hydra:totalItems']) {
    //   hydraData.totalItems = hydraData['hydra:totalItems']
    // }
    // if (hydraData['hydra:itemPosition']) {
    //   hydraData.itemPosition = hydraData['hydra:itemPosition']
    // }

    metadata.type = METADATA_TYPE.ITEM

    return metadata

  }

  /**
   * Méthode de parsing appelé si on est dans un GET Collection
   *
   * @param {AnyJson} hydraData
   */
  private static parseCollection (hydraData: AnyJson): ApiResponse {
    const collectionResponse:ApiResponse = {
      data:hydraData['hydra:member'],
      metadata : Hydra.definedMetadataForCollection(hydraData)
    }

    // collectionResponse.order = {}
    // collectionResponse.search = {}


    // Populate href property for all elements of the collection
    for (const key in collectionResponse.data) {
      const value = collectionResponse.data[key]
      Hydra.populateAllData(value)
    }

    // if (typeof (hydraData['hydra:search']) !== 'undefined') {
    //   const collectionSearch = hydraData['hydra:search']['hydra:mapping']
    //   for (const key in collectionSearch) {
    //     const value = collectionSearch[key]
    //     if (value.variable.indexOf('filter[order]') === 0) {
    //       collectionResponse.order[value.property] = value
    //     } else if (value.variable.indexOf('filter[where]') === 0) {
    //       collectionResponse.search[value.property] = value
    //     }
    //   }
    // }

    return collectionResponse
  }

  private static  definedMetadataForCollection(data:AnyJson){
    const metadata:HydraMetadata = {
      totalItems: data['hydra:totalItems']
    }

    if(data['hydra:view']){
      metadata.firstPage = Hydra.getPageNumber(data['hydra:view']['hydra:first'])
      metadata.lastPage = Hydra.getPageNumber(data['hydra:view']['hydra:last'])
      metadata.nextPage = Hydra.getPageNumber(data['hydra:view']['hydra:next'])
      metadata.previousPage = Hydra.getPageNumber(data['hydra:view']['hydra:previous'])
    }

    metadata.type = METADATA_TYPE.COLLECTION

    return metadata
  }

  private static  getPageNumber(uri:string):number {
    if(uri){
      const number = uri.split('page=').pop()
      return number ? parseInt(number) : 0
    }
    return 0
  }

  /**
   * Hydrate l'objet JSON de façon récursive (afin de gérer les objet nested)
   *
   * @param {AnyJson} data
   */
  private static populateAllData (data: AnyJson): void {
    for (const key in data) {
      const value = data[key]
      if (value instanceof Object) {
        Hydra.populateAllData(value)
      }
    }
  }
}

export default Hydra
