const { DataTypes, Model, where, fn, col } = require('sequelize')

const oldSeries = require('../objects/entities/Series')

class Series extends Model {
  constructor(values, options) {
    super(values, options)

    /** @type {UUIDV4} */
    this.id
    /** @type {string} */
    this.name
    /** @type {string} */
    this.nameIgnorePrefix
    /** @type {string} */
    this.description
    /** @type {UUIDV4} */
    this.libraryId
    /** @type {Date} */
    this.createdAt
    /** @type {Date} */
    this.updatedAt
  }

  static async getAllOldSeries() {
    const series = await this.findAll()
    return series.map(se => se.getOldSeries())
  }

  getOldSeries() {
    return new oldSeries({
      id: this.id,
      name: this.name,
      description: this.description,
      libraryId: this.libraryId,
      addedAt: this.createdAt.valueOf(),
      updatedAt: this.updatedAt.valueOf()
    })
  }

  static updateFromOld(oldSeries) {
    const series = this.getFromOld(oldSeries)
    return this.update(series, {
      where: {
        id: series.id
      }
    })
  }

  static createFromOld(oldSeries) {
    const series = this.getFromOld(oldSeries)
    return this.create(series)
  }

  static createBulkFromOld(oldSeriesObjs) {
    const series = oldSeriesObjs.map(this.getFromOld)
    return this.bulkCreate(series)
  }

  static getFromOld(oldSeries) {
    return {
      id: oldSeries.id,
      name: oldSeries.name,
      nameIgnorePrefix: oldSeries.nameIgnorePrefix,
      description: oldSeries.description,
      libraryId: oldSeries.libraryId
    }
  }

  static removeById(seriesId) {
    return this.destroy({
      where: {
        id: seriesId
      }
    })
  }

  /**
   * Get oldSeries by id
   * @param {string} seriesId 
   * @returns {Promise<oldSeries>}
   */
  static async getOldById(seriesId) {
    const series = await this.findByPk(seriesId)
    if (!series) return null
    return series.getOldSeries()
  }

  /**
   * Check if series exists
   * @param {string} seriesId 
   * @returns {Promise<boolean>}
   */
  static async checkExistsById(seriesId) {
    return (await this.count({ where: { id: seriesId } })) > 0
  }

  /**
   * Get old series by name and libraryId. name case insensitive
   * 
   * @param {string} seriesName 
   * @param {string} libraryId 
   * @returns {Promise<oldSeries>}
   */
  static async getOldByNameAndLibrary(seriesName, libraryId) {
    const series = (await this.findOne({
      where: [
        where(fn('lower', col('name')), seriesName.toLowerCase()),
        {
          libraryId
        }
      ]
    }))?.getOldSeries()
    return series
  }

  /**
   * Initialize model
   * @param {import('../Database').sequelize} sequelize 
   */
  static init(sequelize) {
    super.init({
      id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
        primaryKey: true
      },
      name: DataTypes.STRING,
      nameIgnorePrefix: DataTypes.STRING,
      description: DataTypes.TEXT
    }, {
      sequelize,
      modelName: 'series',
      indexes: [
        {
          fields: [{
            name: 'name',
            collate: 'NOCASE'
          }]
        },
        // {
        //   fields: [{
        //     name: 'nameIgnorePrefix',
        //     collate: 'NOCASE'
        //   }]
        // },
        {
          fields: ['libraryId']
        }
      ]
    })

    const { library } = sequelize.models
    library.hasMany(Series, {
      onDelete: 'CASCADE'
    })
    Series.belongsTo(library)
  }
}

module.exports = Series