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

const NODE_TYPE = require('../../constant/relationship/node-type.constant');

class Node {
  constructor(opt) {
    this._id = null;
    this.label = null;
    this.type = null;

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

  fillObject(opt) {
    this._id = opt._id || new ObjectId().toString();
    this.label = opt.label;
    this.type = opt.type;
  }

  validate() {
    const validation = tv4.validateMultiple(this, Node.schema());
    const isLabelValid = this.validateLabel(this.type, this.label);
    if (!isLabelValid) {
      validation.errors.push(new Error(`Invalid label for type ${this.type}`));
      validation.valid = false;
    }
    return validation;
  }

  // eslint-disable-next-line class-methods-use-this
  validateLabel(type, label) {
    const sortedLabel = Object.keys(label).sort();
    switch (type) {
      case NODE_TYPE.PERSON:
        return _.isEqual(sortedLabel, ['email', 'firstName', 'lastName']);
      case NODE_TYPE.ROOM:
        return _.isEqual(sortedLabel, ['buildingName', 'roomNumber']);
      case NODE_TYPE.ASSESSMENT:
        return _.isEqual(sortedLabel, ['name', 'seriesId', 'status', 'statusDisplay', 'templateId', 'templateType']);
      case NODE_TYPE.GROUP:
        return _.isEqual(sortedLabel, ['name']);
      case NODE_TYPE.DEPARTMENT:
        return _.isEqual(sortedLabel, ['code', 'costCenter', 'description', 'name']);
      case NODE_TYPE.COLLEGE:
      case NODE_TYPE.DIVISION:
      case NODE_TYPE.PROGRAM:
      case NODE_TYPE.TENANT:
      case NODE_TYPE.UNIT:
        return _.isEqual(sortedLabel, ['code', 'name']);
      case NODE_TYPE.INVENTORY:
      default:
        return _.isEqual(sortedLabel, ['name']);
    }
  }

  static schema() {
    return {
      $schema: 'http://json-schema.org/draft-04/schema#',
      id: 'node.schema.json',
      type: 'object',
      additionalProperties: false,
      properties: {
        _id: { type: 'string' },
        label: { type: 'object' },
        type: { enum: Object.values(NODE_TYPE) },
      },
      required: Object.keys(new Node()),
    };
  }
}

module.exports = Node;
