const { ObjectId } = require('bson');
const tv4 = require('tv4');
const { isEqual } = require('lodash');

const CATALOG_TYPE = require('../../constant/library/catalog-type.constant');
const BioDetails = require('./details/bio-details');
const PPEDetails = require('./details/ppe-details');

class LibraryItem {
  constructor(opt) {
    this._id = null;
    this.catalog = null;
    this.name = null;
    this.description = null;
    this.tags = null;
    this.details = null;

    if (opt) {
      this.fillObject({ ...opt });
    }
  }

  fillObject(opt) {
    this._id = new ObjectId(opt._id);
    this.catalog = opt.catalog || null;
    this.name = opt.name || null;
    this.description = opt.description || null;
    this.tags = opt.tags || [];
    switch (opt.catalog) {
      case CATALOG_TYPE.BIOLOGICAL:
        this.details = new BioDetails(opt.details);
        break;
      case CATALOG_TYPE.EQUIPMENT:
        this.details = null;
        break;
      case CATALOG_TYPE.PPE:
        this.details = new PPEDetails(opt.details);
        break;
      case CATALOG_TYPE.SERVICES:
        this.details = null;
        break;
      default:
        this.details = null;
    }
  }

  validate() {
    const validation = tv4.validateMultiple(this, LibraryItem.schema());
    const isDetailsValid = this.validateDetails(this.catalog, this.details);

    if (!isDetailsValid) {
      validation.errors.push(new Error(`Invalid details for catalog ${this.catalog}`));
      validation.valid = false;
    }
    return validation;
  }

  validateDetails(catalog = this.catalog, details = this.details) {
    switch (catalog) {
      case CATALOG_TYPE.PPE:
        return new PPEDetails(details).validate().valid;
      case CATALOG_TYPE.BIOLOGICAL:
        return isEqual(Object.keys(details).sort(), Object.keys(new BioDetails()).sort());
      default:
        return false;
    }
  }

  static schema() {
    return {
      $schema: 'http://json-schema.org/draft-04/schema#',
      id: 'library-item.schema.json',
      title: 'library Item Schema',
      type: 'object',
      additionalProperties: false,
      properties: {
        _id: { type: 'object' },
        catalog: { enum: Object.keys(CATALOG_TYPE) },
        name: { type: 'string' },
        description: { type: ['string', 'null'] },
        tags: {
          type: 'array',
          minItems: 1,
        },
        details: {
          oneOf: [
            { $ref: 'library-item.bio.details.schema.json' },
            { $ref: 'library-item.ppe.details.schema.json' },
            { type: 'null' },
          ],
        },
      },
      required: Object.keys(new LibraryItem()),
    };
  }
}

tv4.addSchema(BioDetails.schema());
tv4.addSchema(PPEDetails.schema());

module.exports = LibraryItem;
