import {
  AddBDProductService,
  GetBDProductsServices,
  UpdateBDAddress,
  UpdateBDIdentification,
  UpdateBDProductService,
  UpdateBDStockSalesCosts
} from '@agiliza/api/domain'
import { ErrorMappers } from '@agiliza/api/mappers'
import { ClienteApi, Configuration } from '@microcredito/client'

import { ProposalDataApiMappers, ProposalDataMappers } from '../../mappers'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from '../shared'

export interface PDBusinessDataRepository {
  getProductsServices(input: GetBDProductsServices['Input']): Promise<GetBDProductsServices['Output']>
  addProductService(input: AddBDProductService['Input']): Promise<AddBDProductService['Output']>
  updateProductService(input: UpdateBDProductService['Input']): Promise<UpdateBDProductService['Output']>
  updateIdentification(input: UpdateBDIdentification['Input']): Promise<UpdateBDIdentification['Output']>
  updateAddress(input: UpdateBDAddress['Input']): Promise<UpdateBDAddress['Output']>
  updateStockSalesCosts(input: UpdateBDStockSalesCosts['Input']): Promise<UpdateBDStockSalesCosts['Output']>
}

export class PDBusinessDataRepositoryImpl implements PDBusinessDataRepository {
  private api: ClienteApi
  private errorAdapter: ErrorMappers.ResponseErrorAdapter
  private bdGetServicesProductsMapper: ProposalDataMappers.BDProductsServicesMapper
  private bdAddProductServiceApiMapper: ProposalDataApiMappers.BDAddProductServiceApiMapper
  private bdUpdateProductServiceApiMapper: ProposalDataApiMappers.BDUpdateProductServiceApiMapper
  private bdUpdateAddressApiMapper: ProposalDataApiMappers.BDUpdateAddressApiMapper
  private bdUpdateIdentificationApiMapper: ProposalDataApiMappers.BDUpdateIdentificationApiMapper
  private bdUpdateAddressMapper: ProposalDataMappers.BDUpdateAddressMapper
  private bdIdentificationMapper: ProposalDataMappers.BDIdentificationMapper
  private bdUpdateStockSalesCostsApiMapper: ProposalDataApiMappers.BDUpdateStockSalesCosts
  private bdUpdateStockSalesCostsMapper: ProposalDataMappers.BDUpdateStockSalesCostsMapper

  constructor(userAgent: string, accessToken: string) {
    this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
    this.bdGetServicesProductsMapper = new ProposalDataMappers.BDProductsServicesMapper()
    this.bdAddProductServiceApiMapper = new ProposalDataApiMappers.BDAddProductServiceApiMapper()
    this.bdUpdateProductServiceApiMapper = new ProposalDataApiMappers.BDUpdateProductServiceApiMapper()
    this.bdUpdateAddressApiMapper = new ProposalDataApiMappers.BDUpdateAddressApiMapper()
    this.bdUpdateAddressMapper = new ProposalDataMappers.BDUpdateAddressMapper()
    this.bdUpdateIdentificationApiMapper = new ProposalDataApiMappers.BDUpdateIdentificationApiMapper()
    this.bdIdentificationMapper = new ProposalDataMappers.BDIdentificationMapper()
    this.bdUpdateStockSalesCostsApiMapper = new ProposalDataApiMappers.BDUpdateStockSalesCosts()
    this.bdUpdateStockSalesCostsMapper = new ProposalDataMappers.BDUpdateStockSalesCostsMapper()

    this.api = new ClienteApi(
      new Configuration({
        basePath: API_URL,
        accessToken,
        headers: {
          'User-Agent': userAgent,
        },
      })
    )
  }

  public getProductsServices = async (input: GetBDProductsServices['Input']): Promise<GetBDProductsServices['Output']> => {
    try {
      const response = await this.api.obterProdutosServicosDadosNegocio({ projetoId: input.projectId })
      return response.map(this.bdGetServicesProductsMapper.mapApiModelToDomain)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public addProductService = async (input: AddBDProductService['Input']): Promise<AddBDProductService['Output']> => {
    try {
      const response = await this.api.criarProdutoServicoDadosNegocio(this.bdAddProductServiceApiMapper.mapDomainToApiModel(input))
      return response.map(this.bdGetServicesProductsMapper.mapApiModelToDomain)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public updateProductService = async (input: UpdateBDProductService['Input']): Promise<UpdateBDProductService['Output']> => {
    try {
      const response = await this.api.atualizaProdutoServicoDadosNegocio(this.bdUpdateProductServiceApiMapper.mapDomainToApiModel(input))
      return response.map(this.bdGetServicesProductsMapper.mapApiModelToDomain)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public updateIdentification = async (input: UpdateBDIdentification['Input']): Promise<UpdateBDIdentification['Output']> => {
    try {
      console.log(this.bdUpdateIdentificationApiMapper.mapDomainToApiModel(input))
      const response = await this.api.atualizarIdentificacaoDadosNegocio(this.bdUpdateIdentificationApiMapper.mapDomainToApiModel(input))
      return this.bdIdentificationMapper.mapApiModelToDomain(response)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public updateAddress = async (input: UpdateBDAddress['Input']): Promise<UpdateBDAddress['Output']> => {
    try {
      const response = await this.api.atualizarEnderecoDadosNegocio(this.bdUpdateAddressApiMapper.mapDomainToApiModel(input))
      return this.bdUpdateAddressMapper.mapApiModelToDomain(response)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public updateStockSalesCosts = async (input: UpdateBDStockSalesCosts['Input']): Promise<UpdateBDStockSalesCosts['Output']> => {
    try {
      const response = await this.api.atualizarEstoqueVendasCustosDadosNegocio(this.bdUpdateStockSalesCostsApiMapper.mapDomainToApiModel(input))
      return this.bdUpdateStockSalesCostsMapper.mapApiModelToDomain(response)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }
}

export class PDBusinessDataRepositoryImplFactory {
  static create(userAgent: UserAgent) {
    const accessToken = localStorage.getItem(SESSION_KEY) || ''
    const repository = new PDBusinessDataRepositoryImpl(mapUserAgentToString(userAgent), accessToken)
    return repository
  }
}
