import { AnyJson, DataPersisterArgs, DataProviderArgs } from '~/types/interfaces'
import UrlBuilder from '~/services/connection/urlBuilder'
import { DENORMALIZER_TYPE, HTTP_METHOD } from '~/types/enums'
import Serializer from '~/services/serializer/serializer'
import DataProvider from '~/services/data/dataProvider'
import BaseDataManager from '~/services/data/baseDataManager'
import { hooksPersister } from '~/services/data/hooks/hookPersister/_import'

/**
 * Le DataPersister a pour rôle de mettre à jour les données via de l'API
 *
 * Il sérialise les données et les envoie à l'API sous la forme d'une requête
 * PUT ou POST, selon les cas. Il fait ensuite appel au DataProvider pour traiter la
 * réponse de l'API et la retourner.
 */
class DataPersister extends BaseDataManager {
  protected hooks = hooksPersister;

  /**
   * Exécute la requête et retourne la réponse désérialisée
   * @param {DataDeleterArgs} queryArguments
   */
  protected async _invoke (queryArguments: DataPersisterArgs): Promise<any> {
    // serialize the data to persist and attach it to the request arguments
    queryArguments.data = Serializer.normalize(queryArguments)

    // build the url according to the url args
    const url = UrlBuilder.build(queryArguments)

    // send the POST / PUT request to the api and retrieve the response
    const response = await DataPersister.request(
      url,
      queryArguments.id ? HTTP_METHOD.PUT : HTTP_METHOD.POST,
      queryArguments
    )

    // Deserialize, post-process and return the response
    return await this.provideResponse(response, queryArguments)
  }

  /**
   * Use a data provider to deserialize, post-process and return the response
   *
   * @param {AnyJson} response
   * @param {DataPersisterArgs} args
   */
  private async provideResponse (response: AnyJson, args: DataPersisterArgs) {

    const deserializedResponse = Serializer.denormalize(response, DENORMALIZER_TYPE.HYDRA)

    const dataProvider = new DataProvider()
    dataProvider.initCtx(this.ctx)
    const dataProviderArgs: DataProviderArgs = {
      type: args.type,
      url: args.url,
      enumType: args.enumType,
      model: args.model,
      rootModel: args.rootModel,
      id: args.id,
      rootId: args.rootId
    }
    return await dataProvider.process(deserializedResponse, dataProviderArgs)
  }
}

export default DataPersister
