import {
  AddCDIdentification,
  AddCDReference,
  AddCDVehicle,
  Address,
  Home,
  InvolvedPerson,
  Reference,
  RG,
  SourceIncome,
  SpousePersonalData,
  UpdateCDAddress,
  UpdateCDHome,
  UpdateCDPersonalData,
  UpdateCDReference,
  UpdateCDSourceIncome,
  UpdateCDSpouseData,
  UpdateCDVehicle,
  Vehicle
} from '@agiliza/api/domain'
import { extractNumbers } from '@agiliza/utils/method'
import {
  EnderecoApiModel,
  ProjetoPessoaEnvolvidaConjugeApiModel,
  ProjetoPessoaEnvolvidaDadosMoradiaApiModel,
  ProjetoPessoaEnvolvidaDadosPessoaisApiModel,
  ProjetoPessoaEnvolvidaFonteRendaApiModel,
  ProjetoPessoaEnvolvidaIdentificacaoApiModel,
  ProjetoPessoaEnvolvidaReferenciaApiModel,
  ProjetoPessoaEnvolvidaRGApiModel,
  ProjetoPessoaEnvolvidaVeiculoApiModel
} from '@microcredito/client'
import {
  AtualiarReferenciaPessoaEnvolvidaRequest,
  AtualizarConjugePessoaEnvolvidaRequest,
  AtualizarDadosMoradiaPessoaEnvolvidaRequest,
  AtualizarDadosPessoaisPessoaEnvolvidaRequest,
  AtualizarEnderecoPessoaEnvolvidaRequest,
  AtualizarFonteRendaPessoaEnvolvidaRequest,
  AtualizarVeiculoPessoaEnvolvidaRequest,
  CriarReferenciaPessoaEnvolvidaRequest,
  CriarVeiculoPessoaEnvolvidaRequest,
  IncluirPessoaEnvolvidaRequest
} from '@microcredito/client/dist/apis/AgenteApi'

import { ApiAdapter } from '../shared'

export class AddInvolvedPersonIdentification implements ApiAdapter<InvolvedPerson['identification'], ProjetoPessoaEnvolvidaIdentificacaoApiModel> {
  public mapBanestesAccountToApi = (
    acc: InvolvedPerson['identification']['account']
  ): ProjetoPessoaEnvolvidaIdentificacaoApiModel['contaBanestes'] => ({
    numeroConta: acc?.number,
    fotoCartao: acc?.cardPicture,
    numeroAgencia: acc?.agencyNumber,
  })

  public mapDateTypeToApi = (dType: InvolvedPerson['identification']['dataType']): ProjetoPessoaEnvolvidaIdentificacaoApiModel['dadosTipo'] => ({
    enquadramento: dType?.framework,
    fazRetirada: dType?.doesWithdrawal,
    porcentagemParticipacao: dType?.participationPercentage ? Number(dType?.participationPercentage) : undefined,
  })

  public mapDomainToApiModel = (domain: InvolvedPerson['identification']): ProjetoPessoaEnvolvidaIdentificacaoApiModel => ({
    id: domain.id,
    nome: domain.name,
    cpfcnpj: extractNumbers(domain.cpfcnpj),
    sexo: domain.gender,
    tipo: domain.type,
    contaBanestes: domain.account ? this.mapBanestesAccountToApi(domain.account) : undefined,
    dadosTipo: domain.dataType ? this.mapDateTypeToApi(domain.dataType) : undefined,
  })
}

export class CDAddIdentificationMapper implements ApiAdapter<AddCDIdentification['Input'], IncluirPessoaEnvolvidaRequest> {
  private identificationApiMapper: AddInvolvedPersonIdentification
  constructor() {
    this.identificationApiMapper = new AddInvolvedPersonIdentification()
  }
  public mapDomainToApiModel = (input: AddCDIdentification['Input']): IncluirPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaEnvolvidaIdentificacaoRequestApiModel: {
      identificacao: this.identificationApiMapper.mapDomainToApiModel(input.identification),
    },
  })
}

export class RGApiAdapter implements ApiAdapter<RG, ProjetoPessoaEnvolvidaRGApiModel> {
  public mapDomainToApiModel = (rg: RG): ProjetoPessoaEnvolvidaRGApiModel => ({
    frente: rg.front || '',
    verso: rg.back || '',
    orgaoExpedidor: rg.dispatcherAgency,
    numero: rg.number,
  })
}

export class CDPersonalDataMapper implements ApiAdapter<InvolvedPerson['personalData'], ProjetoPessoaEnvolvidaDadosPessoaisApiModel> {
  private rgApiAdapter: RGApiAdapter
  constructor() {
    this.rgApiAdapter = new RGApiAdapter()
  }

  public mapDomainToApiModel = (dP: InvolvedPerson['personalData']): ProjetoPessoaEnvolvidaDadosPessoaisApiModel => ({
    dataNascimento: dP?.birthday || undefined,
    emailPrimario: dP?.primaryEmail,
    emailSecundario: dP?.secundaryEmail,
    nomePai: dP?.fathersName,
    nomeMae: dP?.mothersName,
    dependentes: dP?.dependents,
    escolaridade: dP?.schooling,
    rg: dP?.rg ? this.rgApiAdapter.mapDomainToApiModel(dP?.rg) : undefined,
    estadoCivil: dP?.maritalStatus,
    profissao: dP?.occupation,
    telefone: extractNumbers(dP?.mobile),
    telefoneFixo: extractNumbers(dP?.landline),
    usuarioCRAS: dP?.userCRAS,
  })
}

export class CDUpdatePersonalDataMapper implements ApiAdapter<UpdateCDPersonalData['Input'], AtualizarDadosPessoaisPessoaEnvolvidaRequest> {
  private cDPersonalDataMapper: CDPersonalDataMapper
  constructor() {
    this.cDPersonalDataMapper = new CDPersonalDataMapper()
  }
  public mapDomainToApiModel = (input: UpdateCDPersonalData['Input']): AtualizarDadosPessoaisPessoaEnvolvidaRequest => ({
    pessoaId: input.personId,
    projetoId: input.projectId,
    pessoaEnvolvidaDadosPessoaisRequestApiModel: {
      dadosPessoais: this.cDPersonalDataMapper.mapDomainToApiModel(input.personalData),
    },
  })
}

export class CDUpdateAddressApiMapper implements ApiAdapter<UpdateCDAddress['Input'], AtualizarEnderecoPessoaEnvolvidaRequest> {
  private addressApiMapper: AddressApiMapper
  constructor() {
    this.addressApiMapper = new AddressApiMapper()
  }
  public mapDomainToApiModel = (input: UpdateCDAddress['Input']): AtualizarEnderecoPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    projetoPessoaEnvolvidaEnderecoApiModel: {
      comprovante: input.address.proof,
      endereco: this.addressApiMapper.mapDomainToApiModel(input.address),
    },
  })
}

export class AddressApiMapper implements ApiAdapter<Address, EnderecoApiModel> {
  public mapDomainToApiModel = (address: Address): EnderecoApiModel => ({
    bairro: address.district,
    cep: extractNumbers(address.cep),
    estado: address.state,
    logradouro: address.street,
    municipio: address.city,
    numero: address.number,
    complemento: address.complement,
  })
}

export class CDUpdateSourceIncomeApiMapper implements ApiAdapter<UpdateCDSourceIncome['Input'], AtualizarFonteRendaPessoaEnvolvidaRequest> {
  private addressApiMapper: AddressApiMapper

  constructor() {
    this.addressApiMapper = new AddressApiMapper()
  }

  private mapSourceIncomeToApi = (sI: SourceIncome): ProjetoPessoaEnvolvidaFonteRendaApiModel => ({
    cnpj: extractNumbers(sI.cnpj),
    cargoFuncao: sI.position,
    fotoComprovante: sI.proofAddress,
    telefone: extractNumbers(sI.mobile),
    razaoSocial: sI.companyName,
    dataAdmissao: sI.admissionDate || undefined,
    endereco: sI.address ? this.addressApiMapper.mapDomainToApiModel(sI.address) : undefined,
    rendaLiquida: Number(sI.netIncome) / 100,
  })

  public mapDomainToApiModel = (input: UpdateCDSourceIncome['Input']): AtualizarFonteRendaPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    pessoaEnvolvidaFonteRendaRequestApiModel: { fonteRenda: this.mapSourceIncomeToApi(input.sourceIncome) },
  })
}

export class CDUpdateSpouseDataApiMapper implements ApiAdapter<UpdateCDSpouseData['Input'], AtualizarConjugePessoaEnvolvidaRequest> {
  private rgApiAdapter: RGApiAdapter
  constructor() {
    this.rgApiAdapter = new RGApiAdapter()
  }
  private mapSpouseDataToApi = (spouse: SpousePersonalData): ProjetoPessoaEnvolvidaConjugeApiModel => ({
    cpf: extractNumbers(spouse.cpf),
    dataNascimento: spouse.birthday || undefined,
    dependentes: spouse.dependents ? Number(spouse.dependents) : undefined,
    escolaridade: spouse.schooling ? Number(spouse.schooling) : undefined,
    estadoCivil: spouse.maritalStatus ? Number(spouse.maritalStatus) : undefined,
    nome: spouse.name,
    nomeMae: spouse.mothersName,
    nomePai: spouse.fathersName,
    porcentagemParticipacao: spouse.participationPercentage ? Number(spouse.participationPercentage) : undefined,
    profissao: spouse.occupation,
    rg: spouse.rg ? this.rgApiAdapter.mapDomainToApiModel(spouse.rg) : undefined,
    usuarioCRAS: spouse.userCRAS,
    certidaoCasamento: spouse.marriageCertificate || '',
  })
  public mapDomainToApiModel = (input: UpdateCDSpouseData['Input']): AtualizarConjugePessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    projetoPessoaEnvolvidaConjugeApiModel: this.mapSpouseDataToApi(input.spouseData),
  })
}

export class ReferenceApiMapper implements ApiAdapter<Reference, ProjetoPessoaEnvolvidaReferenciaApiModel> {
  public mapDomainToApiModel = (ref: Reference): ProjetoPessoaEnvolvidaReferenciaApiModel => ({
    id: ref.id || undefined,
    conceito: ref.concept,
    foto: ref.photo || '',
    nome: ref.name,
    outrasInformacoes: ref.extraInfo,
    telefone: extractNumbers(ref.telephone),
    tipo: ref.type ? Number(ref.type) : undefined,
  })
}

export class CDAddReferenceApiMapper implements ApiAdapter<AddCDReference['Input'], CriarReferenciaPessoaEnvolvidaRequest> {
  private referenceApiMapper: ReferenceApiMapper
  constructor() {
    this.referenceApiMapper = new ReferenceApiMapper()
  }
  public mapDomainToApiModel = (input: AddCDReference['Input']): CriarReferenciaPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    projetoPessoaEnvolvidaReferenciaApiModel: this.referenceApiMapper.mapDomainToApiModel(input.reference),
  })
}

export class CDUpdateReferenceApiMapper implements ApiAdapter<UpdateCDReference['Input'], AtualiarReferenciaPessoaEnvolvidaRequest> {
  private referenceApiMapper: ReferenceApiMapper
  constructor() {
    this.referenceApiMapper = new ReferenceApiMapper()
  }
  public mapDomainToApiModel = (input: UpdateCDReference['Input']): AtualiarReferenciaPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    referenciaId: input.referenceId,
    projetoPessoaEnvolvidaReferenciaApiModel: this.referenceApiMapper.mapDomainToApiModel(input.reference),
  })
}

export class HomeApiMapper implements ApiAdapter<Home, ProjetoPessoaEnvolvidaDadosMoradiaApiModel> {
  private addressApiAdapter: AddressApiMapper
  constructor() {
    this.addressApiAdapter = new AddressApiMapper()
  }

  public mapDomainToApiModel = (home: Home): ProjetoPessoaEnvolvidaDadosMoradiaApiModel => ({
    endereco: home.address ? this.addressApiAdapter.mapDomainToApiModel(home.address) : undefined,
    escritura: home.deed,
    possuiOnus: home.hasOnus,
    registroEscritura: Number(home.deedRecord),
    resideImovel: home.reside,
    tempoLocal: Number(home.resideTime),
    tempoMunicipio: Number(home.cityResideTime),
    tipo: Number(home.type),
    valorMercado: home.marketValue ? Number(extractNumbers(home.marketValue)) : undefined,
  })
}

export class CDUpdateHomeApiMapper implements ApiAdapter<UpdateCDHome['Input'], AtualizarDadosMoradiaPessoaEnvolvidaRequest> {
  private homeApiMapper: HomeApiMapper
  constructor() {
    this.homeApiMapper = new HomeApiMapper()
  }
  public mapDomainToApiModel = (input: UpdateCDHome['Input']): AtualizarDadosMoradiaPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    projetoPessoaEnvolvidaDadosMoradiaApiModel: this.homeApiMapper.mapDomainToApiModel(input.home),
  })
}

export class VehicleApiMapper implements ApiAdapter<Vehicle, ProjetoPessoaEnvolvidaVeiculoApiModel> {
  public mapDomainToApiModel = (vhcl: Vehicle): ProjetoPessoaEnvolvidaVeiculoApiModel => ({
    id: vhcl.id,
    ano: vhcl.year ? Number(vhcl.year) : undefined,
    documento: vhcl.document,
    marca: vhcl.brand,
    modelo: vhcl.model,
    placa: vhcl.licensePlate.replace(/(\W)/g, ''),
    possuiOnus: vhcl.hasOnus,
    possuiSeguro: vhcl.hasInsurance,
    valorMercado: vhcl.marketValue ? Number(vhcl.marketValue) / 100 : undefined,
  })
}

export class CDAddVehicleApiMapper implements ApiAdapter<AddCDVehicle['Input'], CriarVeiculoPessoaEnvolvidaRequest> {
  private vehicleApiMapper: VehicleApiMapper
  constructor() {
    this.vehicleApiMapper = new VehicleApiMapper()
  }
  public mapDomainToApiModel = (input: AddCDVehicle['Input']): CriarVeiculoPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    projetoPessoaEnvolvidaVeiculoApiModel: this.vehicleApiMapper.mapDomainToApiModel(input.vehicle),
  })
}

export class CDUpdateVehicleApiMapper implements ApiAdapter<UpdateCDVehicle['Input'], AtualizarVeiculoPessoaEnvolvidaRequest> {
  private vehicleApiMapper: VehicleApiMapper
  constructor() {
    this.vehicleApiMapper = new VehicleApiMapper()
  }
  public mapDomainToApiModel = (input: UpdateCDVehicle['Input']): AtualizarVeiculoPessoaEnvolvidaRequest => ({
    projetoId: input.projectId,
    pessoaId: input.personId,
    veiculoId: input.vehicleId,
    projetoPessoaEnvolvidaVeiculoApiModel: this.vehicleApiMapper.mapDomainToApiModel(input.vehicle),
  })
}
