/* eslint-disable class-methods-use-this */
const ObjectId = require('bson').ObjectID;
const clone = require('clone');
const tv4 = require('tv4');

const OCCUPANCY_TYPE = require('../../constant/location/occupancy-type.constant');
const { campusCodeToTenantCode } = require('../../helper/helper');

class ControlArea {
  constructor(controlArea, building = { codeYear: 2016, fireSuppressionCoverage: false }) {
    this._id = new ObjectId();
    this.name = null;
    this.campusCode = null;
    this.tenantCode = null;
    this.buildingId = null;
    this.rooms = [];
    this.occupancy = 'B';
    this.approvedStorage = [];
    this.fireSuppressionCoverage = null;
    this.isOutdoor = false;
    this.exemption = '';
    this.exemptionNotes = '';
    this.squareFootage = 0;
    this.notify = false;

    if (controlArea) {
      this.fillObject(clone(controlArea), building);
    }
  }

  fillObject(controlArea, building) {
    this._id = new ObjectId(controlArea._id);
    // eslint-disable-next-line no-underscore-dangle
    this._createdDate = this._id.getTimestamp();
    this.name = controlArea.name || null;
    this.campusCode = controlArea.campusCode;
    this.tenantCode = controlArea.tenantCode || campusCodeToTenantCode(controlArea.campusCode);
    this.buildingId = controlArea.buildingId || building.buildingId;
    this.approvedStorage = controlArea.approvedStorage || [];
    this.isOutdoor = !!controlArea.isOutdoor || false;
    this.exemption = controlArea.exemption || '';
    this.exemptionNotes = controlArea.exemptionNotes || '';
    this.squareFootage = controlArea.squareFootage || 0;
    if (controlArea.fireSuppressionCoverage) {
      this.fireSuppressionCoverage = controlArea.fireSuppressionCoverage;
    }
    const codeYear = (building && building.codeYear) || 2016;
    const fireSuppressionCoverage = this.getFireSuppresionCoverage(building);
    if (Array.isArray(controlArea.rooms)) {
      this.populateRooms(controlArea, { codeYear, fireSuppressionCoverage });
    }
    this.occupancy = this.findLowestOccupancy(codeYear, this.rooms);
    this.maq = this.buildMaq(codeYear);
    if (codeYear === 2001 && this.occupancy !== 'H8') {
      delete this.maq['Combustible Dust'];
    }
    this.notify = building && typeof building.notify === 'boolean' ? building.notify : !!controlArea.notify;
  }

  getFireSuppresionCoverage(building) {
    if (typeof this.fireSuppressionCoverage === 'string') {
      return this.fireSuppressionCoverage === 'Yes';
    }
    return building.fireSuppressionCoverage;
  }

  buildMaq(codeYear) {
    // Standard units for MAQ are lbs(solid), gal(liquid, liquefied gas), cubic feet(gas)
    let maq = {};
    if (codeYear === 2016) {
      maq = {
        'Combustible Liquid: IIIB': {
          solid: null,
          liquid: 13200,
          gas: null,
        },
        'Cryogenic Flammable': {
          solid: null,
          liquid: 45,
          gas: null,
        },
        'Cryogenic Inert': {
          solid: null,
          liquid: null,
          gas: null,
        },
        'Cryogenic Oxidizing': {
          solid: null,
          liquid: 45,
          gas: null,
        },
        'Explosive: Division 1-1': {
          solid: 1,
          liquid: 1,
          gas: null,
        },
        'Explosive: Division 1-2': {
          solid: 1,
          liquid: 1,
          gas: null,
        },
        'Explosive: Division 1-3': {
          solid: 10,
          liquid: 10,
          gas: null,
        },
        'Explosive: Division 1-4': {
          solid: 50,
          liquid: 50,
          gas: null,
        },
        'Explosive: Division 1-4G': {
          solid: 125,
          liquid: null,
          gas: null,
        },
        'Explosive: Division 1-5': {
          solid: 1,
          liquid: 1,
          gas: null,
        },
        'Explosive: Division 1-6': {
          solid: 1,
          liquid: null,
          gas: null,
        },
        'Flammable Gas': {
          solid: null,
          liquid: null,
          gas: 1000,
        },
        'Flammable Gas Liquefied': {
          solid: null,
          liquid: 150,
          gas: null,
        },
        'Flammable Liquid: IA': {
          solid: null,
          liquid: 30,
          gas: null,
        },
        'Flammable Solid': {
          solid: 125,
          liquid: null,
          gas: null,
        },
        'Organic Peroxide: UD': {
          solid: 1,
          liquid: 1,
          gas: null,
        },
        'Organic Peroxide: I': {
          solid: 5,
          liquid: 5,
          gas: null,
        },
        'Organic Peroxide: II': {
          solid: 50,
          liquid: 50,
          gas: null,
        },
        'Organic Peroxide: III': {
          solid: 125,
          liquid: 125,
          gas: null,
        },
        'Organic Peroxide: IV': {
          solid: null,
          liquid: null,
          gas: null,
        },
        'Organic Peroxide: V': {
          solid: null,
          liquid: null,
          gas: null,
        },
        'Oxidizer: 4': {
          solid: 1,
          liquid: 1,
          gas: null,
        },
        'Oxidizer: 3': {
          solid: 10,
          liquid: 10,
          gas: null,
        },
        'Oxidizer: 2': {
          solid: 250,
          liquid: 250,
          gas: null,
        },
        'Oxidizer: 1': {
          solid: 4000,
          liquid: 4000,
          gas: null,
        },
        'Oxidizing Gas': {
          solid: null,
          liquid: null,
          gas: 1500,
        },
        'Oxidizing Gas Liquefied': {
          solid: null,
          liquid: 150,
          gas: null,
        },
        Pyrophoric: {
          solid: 4,
          liquid: 4,
          gas: 50,
        },
        'Unstable Reactive: 4': {
          solid: 1,
          liquid: 1,
          gas: 10,
        },
        'Unstable Reactive: 3': {
          solid: 5,
          liquid: 5,
          gas: 50,
        },
        'Unstable Reactive: 2': {
          solid: 50,
          liquid: 50,
          gas: 750,
        },
        'Unstable Reactive: 1': {
          solid: null,
          liquid: null,
          gas: null,
        },
        'Water Reactive: 3': {
          solid: 5,
          liquid: 5,
          gas: null,
        },
        'Water Reactive: 2': {
          solid: 50,
          liquid: 50,
          gas: null,
        },
        'Water Reactive: 1': {
          solid: null,
          liquid: null,
          gas: null,
        },
        Corrosive: {
          solid: 5000,
          liquid: 500,
          gas: 810,
        },
        'Corrosive Liquefied': {
          solid: null,
          liquid: 150,
          gas: null,
        },
        'Highly Toxic': {
          solid: 10,
          liquid: 10,
          gas: 20,
        },
        'Highly Toxic Liquefied': {
          solid: null,
          liquid: 4,
          gas: null,
        },
        Toxic: {
          solid: 500,
          liquid: 500,
          gas: 810,
        },
        'Toxic Liquefied': {
          solid: null,
          liquid: 150,
          gas: null,
        },
      };
      if (this.occupancy === 'M' || this.occupancy === 'S') {
        maq['Flammable Liquid: IB, IC & Combustible Liquid: II & Combustible Liquid: IIIA'] = {
          solid: null,
          liquid: 1600,
          gas: null,
        };
      } else {
        maq['Combustible Liquid: II'] = {
          solid: null,
          liquid: 120,
          gas: null,
        };
        maq['Combustible Liquid: IIIA'] = {
          solid: null,
          liquid: 330,
          gas: null,
        };
        maq['Flammable Liquid: IA'] = {
          solid: null,
          liquid: 30,
          gas: null,
        };
        maq['Flammable Liquid: IB, IC'] = {
          solid: null,
          liquid: 120,
          gas: null,
        };
        maq['Flammable Liquid: IA, IB, IC'] = {
          solid: null,
          liquid: 120,
          gas: null,
        };
      }
    } else if (codeYear === 2001) {
      maq = {
        'Combustible Liquid: II': {
          solid: null,
          liquid: 120,
          gas: null,
        },
        'Combustible Liquid: IIIA': {
          solid: null,
          liquid: 330,
          gas: null,
        },
        'Combustible Liquid: IIIB': {
          solid: null,
          liquid: 13200,
          gas: null,
        },
        'Combustible Dust': {
          solid: 1, // cubic feet
          liquid: null,
          gas: null,
        },
        'Combustible Fiber: Loose': {
          solid: 100, // cubic feet
          liquid: 0,
          gas: null,
        },
        'Combustible Fiber: Bailed': {
          solid: 1000, // cubic feet
          liquid: 0,
          gas: null,
        },
        'Cryogenic, Flammable or Oxidizing': {
          solid: null,
          liquid: 45,
          gas: null,
        },
        'Explosive Material (CFC2001)': {
          solid: 0,
          liquid: 0,
          gas: null,
        },
        'Flammable Solid': {
          solid: 125,
          liquid: null,
          gas: null,
        },
        'Flammable Gas': {
          solid: null,
          liquid: null,
          gas: 750,
        },
        'Flammable Gas Liquefied': {
          solid: null,
          liquid: 15, // gallons
          gas: null,
        },
        'Flammable Liquid: IA': {
          solid: null,
          liquid: 30,
          gas: null,
        },
        'Flammable Liquid: IB': {
          solid: null,
          liquid: 60, // gallons
          gas: null,
        },
        'Flammable Liquid: IC': {
          solid: null,
          liquid: 90, // gallons
          gas: null,
        },
        'Flammable Liquid: IA, IB, IC': {
          solid: null,
          liquid: 120,
          gas: null,
        },
        'Organic Peroxide: UD': {
          solid: 0,
          liquid: 0,
          gas: null,
        },
        'Organic Peroxide: I': {
          solid: 5,
          liquid: 5,
          gas: null,
        },
        'Organic Peroxide: II': {
          solid: 50,
          liquid: 50,
          gas: null,
        },
        'Organic Peroxide: III': {
          solid: 125,
          liquid: 125,
          gas: null,
        },
        'Organic Peroxide: IV': {
          solid: 500,
          liquid: 500,
          gas: null,
        },
        'Organic Peroxide: V': {
          solid: null,
          liquid: null,
          gas: null,
        },
        'Oxidizer: 4': {
          solid: 0,
          liquid: 0,
          gas: null,
        },
        'Oxidizer: 3': {
          solid: 10,
          liquid: 10,
          gas: null,
        },
        'Oxidizer: 2': {
          solid: 250,
          liquid: 250,
          gas: null,
        },
        'Oxidizer: 1': {
          solid: 4000,
          liquid: 4000,
          gas: null,
        },
        'Oxidizing Gas': {
          solid: null,
          liquid: null,
          gas: 1500,
        },
        'Oxidizing Gas Liquefied': {
          solid: null,
          liquid: 15, // in gallons
          gas: null,
        },
        Pyrophoric: {
          solid: 0,
          liquid: 0,
          gas: 0,
        },
        'Unstable Reactive: 4': {
          solid: 0,
          liquid: 0,
          gas: 0,
        },
        'Unstable Reactive: 3': {
          solid: 5,
          liquid: 5,
          gas: 50,
        },
        'Unstable Reactive: 2': {
          solid: 50,
          liquid: 50,
          gas: 750,
        },
        'Unstable Reactive: 1': {
          solid: null,
          liquid: null,
          gas: null,
        },
        'Water Reactive: 3': {
          solid: 5,
          liquid: 5,
          gas: null,
        },
        'Water Reactive: 2': {
          solid: 50,
          liquid: 50,
          gas: null,
        },
        'Water Reactive: 1': {
          solid: null,
          liquid: null,
          gas: null,
        },
        Corrosive: {
          solid: 5000,
          liquid: 500,
          gas: 810,
        },
        'Highly Toxic': {
          solid: 10,
          liquid: 10,
          gas: 0,
        },
        'Irritant (CFC2001)': {
          solid: null,
          liquid: null,
          gas: 810,
        },
        'Other Health Hazard Material (CFC2001)': {
          solid: null,
          liquid: null,
          gas: 810,
        },
        'Sensitizer (CFC2001)': {
          solid: null,
          liquid: null,
          gas: 810,
        },
        Toxic: {
          solid: 500,
          liquid: 500,
          gas: 810,
        },
      };
    }
    return maq;
  }

  validate() {
    return tv4.validateMultiple(this, ControlArea.schema());
  }

  findLowestOccupancy(codeYear, rooms) {
    // for 2016 code year: B(A,B E, F, I, R) < L < S&M < H (1-5)
    // for 2001 code year: B < H8
    const occupanyByRank = {};
    OCCUPANCY_TYPE[codeYear].forEach((o) => {
      occupanyByRank[o.value] = o.sort;
    });
    let type;
    if (!rooms || !rooms.length) {
      type = 'B';
    } else {
      const occupancies = Array.from(new Set(rooms.map((r) => r.occupancy)));
      type = occupancies.reduce((acc, cur) => (!acc || occupanyByRank[cur] < occupanyByRank[acc] ? cur : acc), null);
    }
    const occupancy = occupanyByRank[type] === 0 ? 'B' : type;
    return occupancy;
  }

  populateRooms(controlArea, { codeYear, fireSuppressionCoverage }) {
    const possibleOccupancies = OCCUPANCY_TYPE[codeYear || 2016]
      .filter((o) => !(o.value === 'H8' || o.value === 'L') || (fireSuppressionCoverage && !this.isOutdoor))
      .map((o) => o.value);

    controlArea.rooms.forEach((r) => {
      const room = { ...r };
      if (!possibleOccupancies.some((o) => o === room.occupancy)) {
        room.occupancy = 'B';
      }
      this.rooms.push(room);
    });
  }

  classifications(type) {
    switch (type) {
      case 'healthHazards':
        return [
          'Corrosive',
          'Toxic',
          'Highly Toxic',
          'Corrosive Liquefied',
          'Toxic Liquefied',
          'Highly Toxic Liquefied',
        ];
      case 'canLiquefied':
        return ['Oxidizing', 'Corrosive', 'Toxic', 'Flammable Gas'];
      default:
        return [];
    }
  }

  convertToBand(band) {
    let cryogenic = [];
    switch (true) {
      case !!band.match('Liquefied'):
        return [
          { name: band.split(' Liquefied')[0], class: [] },
          { name: 'Liquefied Gas', class: [] },
        ];
      case !!band.match('Cryogenic'):
        cryogenic = [{ name: 'Cryogenic', class: [] }];
        if (band.match('Flammable')) {
          cryogenic.push({ name: 'Flammable Gas', class: [] });
        } else if (band.match('Oxidizing')) {
          cryogenic.push({ name: 'Oxidizing Gas', class: [] });
        } else if (band.match('Inert')) {
          cryogenic[0].class.push('Inert');
        }
        return cryogenic;
      case !!band.match('Flammable Liquid'):
        return [
          {
            name: 'Flammable Liquid',
            class: band
              .split(': ')[1]
              .split(',')
              .map((i) => i.trim()),
          },
        ];
      case !!band.match('Oxidizer'):
        return [{ name: 'Oxidizers', class: [`Class ${band.split(': ')[1]}`] }];
      case !!band.match(':'):
        return [{ name: band.split(': ')[0], class: [band.split(': ')[1]] }];
      default:
        return [{ name: band, class: [] }];
    }
  }

  static schema() {
    return {
      $schema: 'http://json-schema.org/draft-04/schema#',
      id: 'control-area.schema.json',
      type: 'object',
      additionalProperties: false,
      properties: {
        _id: { type: ['object', 'null'] },
        _createdDate: { type: 'object' },
        name: { type: ['string'] },
        campusCode: { type: ['string'] },
        tenantCode: { type: ['string'] },
        buildingId: { type: ['string'] },
        rooms: { type: 'array', item: { type: 'object' } },
        occupancy: { type: ['string'] },
        fireSuppressionCoverage: { type: ['null', 'string'] },
        approvedStorage: { type: 'array', item: { type: 'string' } },
        isOutdoor: { type: 'boolean' },
        exemption: { type: 'string' },
        exemptionNotes: { type: 'string' },
        squareFootage: { type: 'number' },
        codeYear: { type: 'number' },
        maq: { type: 'object' },
        notify: { type: 'boolean' },
      },
      required: Object.keys(new ControlArea()),
    };
  }
}

module.exports = ControlArea;
