export type DocumentTypeIndex = 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 11;
export type DIVEDocumentTypeIndex = 1 | 2 | 3 | 6 | 7 | 9 | 10 | 11;
export type DocumentTypeName = 'DL' | 'IC' | 'Passport' | 'PassportCard' | 'GreenCard' | 'InternationalId' | 'Barcode' | 'FaceAuthorization' | 'EmploymentAuthorization';
export type HumanName = 'Driver\'s License' | 'Identification Card' | 'Passport' | 'US Passport Card' | 'Green Card' | 'International ID' | '1-D and 2-D Barcodes' | 'Face Authorization' | 'Employment Authorization';
export type ImageSource = 'video' | 'file';

export enum DocumentTypeIDs {
  'DL' = 1,
  'IC' = 1,
  'Passport' = 2,
  'PassportCard' = 3,
  'GreenCard' = 6,
  'InternationalId' = 7,
  'Barcode' = 11,
  'FaceAuthorization' = 10,
  'EmploymentAuthorization' = 9,
}

export interface DocumentRecord {
  name: DocumentTypeName,
  id: DocumentTypeIndex,
  diveDocumentID: DIVEDocumentTypeIndex,
  nName: string,
  humanName: HumanName,
}

interface DocumentType {
  readonly items: DocumentRecord[],
  length: number,
  ids(): DocumentTypeIndex[],
  names(): DocumentTypeName[],
  nameById(id: DocumentTypeIndex | 0): DocumentTypeName | '',
  humanNameById(id: DocumentTypeIndex | 0): HumanName | '',
  humanNames(): HumanName[],
  humanNameByName(name: DocumentTypeName): HumanName | '',
  idByName(name: DocumentTypeName): DocumentTypeIndex | 0,
  idsByNames(names: DocumentTypeName[]): (DocumentTypeIndex | 0)[],
  recordById(id: DocumentTypeIndex | 0): DocumentRecord | null,
  setHumanName(names): void,
}

const documentType: DocumentType = {
  items: [
    {
      name: 'DL',
      id: 1,
      diveDocumentID: 1,
      nName: 'dl',
      humanName: 'Driver\'s License',
    },
    {
      name: 'IC',
      id: 4,
      diveDocumentID: 1,
      nName: 'ic',
      humanName: 'Identification Card',
    },
    {
      name: 'Passport',
      id: 2,
      diveDocumentID: 2,
      nName: 'passp',
      humanName: 'Passport',
    },
    {
      name: 'PassportCard',
      id: 3,
      diveDocumentID: 3,
      nName: 'passpcard',
      humanName: 'US Passport Card',
    },
    {
      name: 'GreenCard',
      id: 6,
      diveDocumentID: 6,
      nName: 'gc',
      humanName: 'Green Card',
    },
    {
      name: 'InternationalId',
      id: 7,
      diveDocumentID: 7,
      nName: 'iid',
      humanName: 'International ID',
    },
    {
      name: 'EmploymentAuthorization',
      id: 9,
      diveDocumentID: 9,
      nName: 'ea',
      humanName: 'Employment Authorization',
    },
    {
      name: 'Barcode',
      id: 11,
      diveDocumentID: 11,
      nName: 'barcode',
      humanName: '1-D and 2-D Barcodes',
    },
    {
      name: 'FaceAuthorization',
      id: 10,
      diveDocumentID: 10,
      nName: 'faceauth',
      humanName: 'Face Authorization',
    },
  ],
  get length() {
    return this.items.length;
  },
  ids() {
    return this.items.map((item) => item.id);
  },
  names() {
    return this.items.map((item) => item.name);
  },
  nameById(id) {
    const res = this.items.filter((item) => item.id === id);
    return res.length ? res[0].name : '';
  },
  humanNameById(id) {
    const res = this.items.filter((item) => item.id === id);
    return res.length ? res[0].humanName : '';
  },
  humanNames() {
    const names: HumanName[] = [];
    this.items.forEach((item) => {
      names[item.id] = item.humanName;
    });
    return names;
  },
  humanNameByName(name) {
    const lowerName = name.toLowerCase();
    const record = this.items.find((item) => item.name.toLowerCase() === lowerName);
    if (record) {
      return record.humanName;
    }
    return '';
  },
  setHumanName(names) {
    Object.keys(names).forEach((key) => {
      const record = this.items.find((item) => item.name === key);
      record.humanName = names[key];
    });
  },
  /**
   * return object's id by its name
   * @param {string} name
   * @returns {Number} id of element by its name or 0 if name not found
   */
  idByName(name) {
    const lowerName = name.toLowerCase();
    if (this.items && this.items.length > 0) {
      const item = this.items.find((record) => record?.name.toLowerCase() === lowerName);
      return item?.id || 0;
    }
    return 0;
  },
  /**
   * return ids by names
   * @param {[string]} names
   * @return {[Number]}
   */
  idsByNames(names) {
    return names.map(this.idByName.bind(this));
  },
  /**
   * return type item { name: String, id: Number, nName: String, humanName: String }
   * @param {number} id
   */
  recordById(id) {
    if (id === 0) return null;
    for (let i = 0; i <= this.length; i += 1) {
      if (this.items[i].id === id) return this.items[i];
    }
    return null;
  },
};

export default documentType;
