import { GetProjectContext, GetProjects, SubmitProjects } from '@agiliza/api/domain'
import { AgenteApi, Configuration } from '@microcredito/client'

import { ErrorMappers, ProjectMappers } from '../mappers'
import { ProjectApiMappers } from '../mappers/api'
import { ContextoProjeto } from '../mappers/domain/project'
import { API_URL, mapUserAgentToString, SESSION_KEY, UserAgent } from './shared'

export interface ProjectRepository {
  getContext(): Promise<GetProjectContext['Output']>
  getProjects(input: GetProjects['Input']): Promise<GetProjects['Output']>
  submitProjects(input: SubmitProjects['Input']): Promise<SubmitProjects['Output']>
}

export class ProjectRepositoryImpl implements ProjectRepository {
  private api: AgenteApi
  private errorAdapter: ErrorMappers.ResponseErrorAdapter
  private projectStatusMapper: ProjectMappers.GetProjectContextMapper
  private getProjectApiMapper: ProjectApiMappers.GetProjectsApiMapper
  private projectMapper: ProjectMappers.ProjectMapper

  constructor(userAgent: string, accessToken: string) {
    this.errorAdapter = new ErrorMappers.ResponseErrorAdapter()
    this.projectStatusMapper = new ProjectMappers.GetProjectContextMapper()
    this.projectMapper = new ProjectMappers.ProjectMapper()
    this.getProjectApiMapper = new ProjectApiMappers.GetProjectsApiMapper()
    this.projectMapper = new ProjectMappers.ProjectMapper()

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

  public getContext = async (): Promise<GetProjectContext['Output']> => {
    try {
      const contexto: ContextoProjeto = { situacoes: await this.api.obterSituacoesProjeto() }
      return this.projectStatusMapper.mapApiModelToDomain(contexto)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public getProjects = async (input: GetProjects['Input']): Promise<GetProjects['Output']> => {
    try {
      const response = await this.api.buscarProjetos(this.getProjectApiMapper.mapDomainToApiModel(input))
      return response.map(this.projectMapper.mapApiModelToDomain)
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }

  public submitProjects = async (input: SubmitProjects['Input']): Promise<SubmitProjects['Output']> => {
    try {
      await this.api.submeterProjetos({ submeterProjetosRequestApiModel: { ids: input.ids } })
    } catch (e) {
      const result = await this.errorAdapter.mapApiModelToDomain(e)
      throw result
    }
  }
}

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