const moji = require('moji');
const { Schema } = require('mongoose');

const {
  normalizeTitle,
  normalizeAuthors,
  normalizeDescription,
} = require('../../lib/normalize');
const connection = require('../').createConnection();

const bookSchema = new Schema({
  _id: { // ASIN
    type: String,
    index: true,
    unique: true,
    required: true,
  },
  processing: {
    type: Boolean,
    index: true,
    default: false,
  },
  active: {
    type: Boolean,
    index: true,
    default: false,
  },
  disable: {
    type: Boolean,
    index: true,
    default: false,
  },
  title: String,
  titleReading: String,
  description: String,
  url: String,
  image: String,
  authors: [String],
  authorsReading: String,
  publisher: String,
  publishedAt: Date,
  releasedAt: Date,
  seriesId: {
    type: String,
    index: true,
  },
}, {
  timestamps: true,
});

bookSchema.pre('save', function normalize (next) {
  if (this.title) { this.title = normalizeTitle(this.title); }
  if (this.authors) { this.authors = normalizeAuthors(this.authors); }
  if (this.description) {
    this.description = normalizeDescription(this.description);
  }
  next();
});

class BookClass {
  static async firstOrCreate(query, doc = query) {
    const book = await this.findOne(query);
    if (book) { return { book, newRecord: false }; }
    return { book: await this.create(doc), newRecord: true };
  }

  static firstOrCreateById(_id, doc = {}) {
    return this.firstOrCreate({ _id }, { _id, ...doc });
  }

  // for self-updating
  static whereNeedsUpdate() {
    const oneDayBefore = new Date(Date.now() - (23 * 60 * 60 * 1000));
    return this
      .where({ processing: false, disable: false })
      .or([{ active: false }, { updatedAt: { '$lt': oneDayBefore } }]);
  }
  static limitNeedsUpdate() { return this.limit(10); }
  static entriesNeedsUpdate() {
    const criteria = this.whereNeedsUpdate();
    return this.limitNeedsUpdate.call(criteria);
  }

  static async createOrUpdateByMyxItem({
    asin, authors, productImage, sortableAuthors, sortableTitle, title,
  }) {
    const params = {
      authors: extractAuthors(authors),
      authorsReading: sortableAuthors,
      image: productImage,
      title,
      titleReading: sortableTitle,
    };
    let book = await this.findById(asin);
    if (book == null) { book = new this({ _id: asin }); }
    return await book.set(params).save();
  }
}
bookSchema.loadClass(BookClass);

const Book = connection.model('Book', bookSchema);
Book.shcema = bookSchema;

module.exports = Book;

const extractAuthors = authors => (
  moji(authors)
    .convert('ZStoHS').toString()
    .split(/[、､，,]+\s*/g)
);

@@ -687,16 +687,50 @@
 rs: 
-%5BString%5D
+%7B%0A    type: %5BString%5D,%0A    default: %5B%5D,%0A  %7D
 ,%0A  
@@ -1252,21 +1252,18 @@
 , doc = 
-query
+%7B%7D
 ) %7B%0A    
@@ -1363,24 +1363,30 @@
     return %7B
+%0A     
  book: await
@@ -1402,13 +1402,36 @@
 ate(
-doc),
+%7B ...query, ...doc %7D),%0A     
  new
@@ -1442,16 +1442,21 @@
 rd: true
+,%0A   
  %7D;%0A  %7D%0A
@@ -1452,24 +1452,36 @@
     %7D;%0A  %7D%0A%0A
+  // @async%0A
   static fir
@@ -1555,23 +1555,11 @@
  %7D, 
-%7B _id, ...
 doc
- %7D
 );%0A 

refactor book model methods