const axios = require('axios')
const Logger = require('../Logger')

class FantLab {
  // 7 - other
  // 11 - essay
  // 12 - article
  // 22 - disser
  // 23 - monography
  // 24 - study
  // 25 - encyclopedy
  // 26 - magazine
  // 46 - sketch
  // 47 - reportage
  // 49 - excerpt
  // 51 - interview
  // 52 - review
  // 55 - libretto
  // 56 - anthology series
  // 57 - newspaper
  // types can get here https://api.fantlab.ru/config.json
  _filterWorkType = [7, 11, 12, 22, 23, 24, 25, 26, 46, 47, 49, 51, 52, 55, 56, 57]
  _baseUrl = 'https://api.fantlab.ru'

  constructor() { }

  async search(title, author) {
    let searchString = encodeURIComponent(title)
    if (author) {
      searchString += encodeURIComponent(' ' + author)
    }
    const url = `${this._baseUrl}/search-works?q=${searchString}&page=1&onlymatches=1`
    Logger.debug(`[FantLab] Search url: ${url}`)
    const items = await axios.get(url).then((res) => {
      return res.data || []
    }).catch(error => {
      Logger.error('[FantLab] search error', error)
      return []
    })

    return Promise.all(items.map(async item => await this.getWork(item))).then(resArray => {
      return resArray.filter(res => res)
    })
  }

  async getWork(item) {
    const { work_id, work_type_id } = item

    if (this._filterWorkType.includes(work_type_id)) {
      return null
    }

    const url = `${this._baseUrl}/work/${work_id}/extended`
    const bookData = await axios.get(url).then((resp) => {
      return resp.data || null
    }).catch((error) => {
      Logger.error(`[FantLab] work info request for url "${url}" error`, error)
      return null
    })

    return this.cleanBookData(bookData)
  }

  async cleanBookData(bookData) {
    let { authors, work_name_alts, work_id, work_name, work_year, work_description, image, classificatory, editions_blocks } = bookData

    const subtitle = Array.isArray(work_name_alts) ? work_name_alts[0] : null
    const authorNames = authors.map(au => (au.name || '').trim()).filter(au => au)

    const imageAndIsbn = await this.tryGetCoverFromEditions(editions_blocks)

    const imageToUse = imageAndIsbn?.imageUrl || image

    return {
      id: work_id,
      title: work_name,
      subtitle: subtitle || null,
      author: authorNames.length ? authorNames.join(', ') : null,
      publisher: null,
      publishedYear: work_year,
      description: work_description,
      cover: imageToUse ? `https://fantlab.ru${imageToUse}` : null,
      genres: this.tryGetGenres(classificatory),
      isbn: imageAndIsbn?.isbn || null
    }
  }

  tryGetGenres(classificatory) {
    if (!classificatory || !classificatory.genre_group) return []

    const genresGroup = classificatory.genre_group.find(group => group.genre_group_id == 1) // genres and subgenres

    // genre_group_id=2 - General Characteristics
    // genre_group_id=3 - Arena
    // genre_group_id=4 - Duration of action
    // genre_group_id=6 - Story moves
    // genre_group_id=7 - Story linearity
    // genre_group_id=5 - Recommended age of the reader

    if (!genresGroup || !genresGroup.genre || !genresGroup.genre.length) return []

    const rootGenre = genresGroup.genre[0]

    const { label } = rootGenre

    return [label].concat(this.tryGetSubGenres(rootGenre))
  }

  tryGetSubGenres(rootGenre) {
    if (!rootGenre.genre || !rootGenre.genre.length) return []
    return rootGenre.genre.map(g => g.label).filter(g => g)
  }

  async tryGetCoverFromEditions(editions) {
    if (!editions) {
      return null
    }

    // 30 = audio, 10 = paper
    // Prefer audio if available
    const bookEditions = editions['30'] || editions['10']
    if (!bookEditions || !bookEditions.list || !bookEditions.list.length) {
      return null
    }

    const lastEdition = bookEditions.list.pop()

    const editionId = lastEdition['edition_id']
    const isbn = lastEdition['isbn'] || null // get only from paper edition

    return {
      imageUrl: await this.getCoverFromEdition(editionId),
      isbn
    }
  }

  async getCoverFromEdition(editionId) {
    if (!editionId) return null
    const url = `${this._baseUrl}/edition/${editionId}`

    const editionInfo = await axios.get(url).then((resp) => {
      return resp.data || null
    }).catch(error => {
      Logger.error(`[FantLab] search cover from edition with url "${url}" error`, error)
      return null
    })

    return editionInfo?.image || null
  }
}

module.exports = FantLab