const UB = require('@unitybase/ub')
const App = UB.App
/* global org_employeeonstaff, TubDataStore, ubs_numcounter */
// eslint-disable-next-line camelcase
const me = org_employeeonstaff

me.on('update:before', assignCaptions)
me.on('update:after', doAfterUpdate)
me.on('insert:before', generateDefaultCodeAndCaption)
me.on('insert:after', doAfterInsert)
me.on('delete:after', doAfterDelete)
me.entity.addMethod('updatePendingStaffUnitCaptions')

/**
 * Updates all multilingual captions for org_staffunit
 * @method updatestaffunitcaption
 * @memberOf org_employeeonstaff_ns.prototype
 * @memberOfModule @unitybase/org
 * @param {Number} staffUnitID
 */
me.updatestaffunitcaption = function (staffUnitID) {
  const staffUnit = UB.DataStore('org_staffunit')
  const updParams = {
    ID: staffUnitID,
    [`caption_${App.defaultLang}^`]: ''
  }
  staffUnit.run('update', {
    fieldList: [],
    caller: me.entity.name,
    execParams: updParams,
    __skipOptimisticLock: true
  })
}

/**
 * Sets proper values for org_staffunit.captions. Can be called from scheduler
 * @method updatePendingStaffUnitCaptions
 * @memberOf org_employeeonstaff_ns.prototype
 * @memberOfModule @unitybase/org
 * @published
 */
me.updatePendingStaffUnitCaptions = function () {
  console.log('** updatePendingStaffUnitCaptions started')

  const pendingStoreName = me.entity.name + '_pending'
  const pendingItemsToUpdate = UB.Repository(pendingStoreName)
    .attrs(['ID', 'emponstaffID.staffUnitID'])
    .where('updateDate', '<=', new Date())
    .selectAsObject({
      'emponstaffID.staffUnitID': 'staffUnitID'
    })
  if (!pendingItemsToUpdate.length) {
    return
  }

  const pendingStore = UB.DataStore(pendingStoreName)
  const updatedStaffUnitIDs = []

  for (const { staffUnitID, ID } of pendingItemsToUpdate) {
    if (!updatedStaffUnitIDs.includes(staffUnitID)) {
      updatedStaffUnitIDs.push(staffUnitID)
      me.updatestaffunitcaption(staffUnitID)
    }

    pendingStore.run('delete', {
      fieldList: [],
      execParams: {
        ID
      },
      __skipOptimisticLock: true
    })
  }

  console.log('** updatePendingStaffUnitCaptions ends')
}

/**
 * Schedules the updates of the `org_staffunit` captions based on `org_employeeonstaff` `mi_dateFrom` and/or `mi_dateTo`
 * @method scheduleUpdate
 * @memberOf org_employeeonstaff_ns.prototype
 * @memberOfModule @unitybase/org
 * @param {ubMethodParams} ctxt
 * @param {string} action One of 'insert', 'update' or 'delete'
 */
me.scheduleUpdate = function (ctxt, action) {
  const execParams = ctxt.mParams.execParams
  const startDate = execParams.mi_dateFrom
  const endDate = execParams.mi_dateTo
  if (!startDate && !endDate) {
    return
  }

  switch (action) {
    case 'insert':
    case 'update':
      if (startDate) {
        upsertPendingAction(execParams.ID, startDate, 'START_DATE')
      }

      if (endDate) {
        upsertPendingAction(execParams.ID, endDate, 'END_DATE')
      }
      break

    case 'delete':
      return deletePendingAction(execParams.ID)
  }
}

/**
 * Updates all multilingual captions for org_staffunit
 * @private
 * @param {ubMethodParams} ctxt
 */
function doAfterUpdate (ctxt) {
  const params = ctxt.mParams
  const execParams = params.execParams
  const staffUnitID = execParams.staffUnitID
  me.scheduleUpdate(ctxt, 'update')
  if (params.caller !== 'org_staffunit') {
    const store = ctxt.dataStore
    const dataName = store.currentDataName
    store.currentDataName = TubDataStore.DATA_NAMES.BEFORE_UPDATE
    const oldStaffUnitID = store.get('staffUnitID') || execParams.staffUnitID
    store.currentDataName = dataName
    if (staffUnitID) {
      me.updatestaffunitcaption(staffUnitID)
    }
    if (staffUnitID !== oldStaffUnitID) {
      me.updatestaffunitcaption(oldStaffUnitID)
    }
  }
}

/**
 * Updates all multilingual captions for org_staffunit
 * @private
 * @param {ubMethodParams} ctxt
 */
function doAfterDelete (ctxt) {
  const store = ctxt.dataStore
  const dataName = store.currentDataName
  store.currentDataName = TubDataStore.DATA_NAMES.BEFORE_DELETE
  const staffUnitID = store.get('staffUnitID')
  store.currentDataName = dataName
  me.updatestaffunitcaption(staffUnitID)
  me.scheduleUpdate(ctxt, 'delete')
}

/**
 * Updates all multilingual captions for org_staffunit
 * @private
 * @param {ubMethodParams} ctxt
 */
function doAfterInsert (ctxt) {
  me.scheduleUpdate(ctxt, 'insert')
  me.updatestaffunitcaption(ctxt.mParams.execParams.staffUnitID)
}

/**
 * Generate default tabNo (Employee #) and set multilingual captions to execParams.
 * Called before insertion
 * @private
 * @param {ubMethodParams} ctxt
 */
function generateDefaultCodeAndCaption (ctxt) {
  ubs_numcounter.generateAutoIncrementalCode(ctxt, 'tabNo')
  return assignCaptions(ctxt)
}
/**
 * Assigns properly values for all multilingual captions to execParams before insert or update
 * @private
 * @param {ubMethodParams} ctxt
 */
function assignCaptions (ctxt) {
  const execParams = ctxt.mParams.execParams

  let { staffUnitID, tabNo, employeeID, employeeOnStaffType } = execParams
  if (!tabNo || !staffUnitID || !employeeID || !employeeOnStaffType) {
    const currentRow = UB.Repository(me.entity.name)
      .attrs(['tabNo', 'staffUnitID', 'employeeID', 'employeeOnStaffType'])
      .where('[ID]', '=', execParams.ID).selectSingle()
    if (!currentRow) return
    employeeID = employeeID || currentRow.employeeID
    tabNo = tabNo || currentRow.tabNo
    staffUnitID = staffUnitID || currentRow.staffUnitID
    employeeOnStaffType = employeeOnStaffType || currentRow.employeeOnStaffType
  }
  const supportedLangs = me.entity.connectionConfig.supportLang
  const depFieldList = []
  const empFieldList = []
  const eosTypeFieldList = []
  supportedLangs.forEach(function (lang) {
    const suffix = '_' + lang + '^'
    eosTypeFieldList.push('name' + suffix)
    depFieldList.push('parentID.caption' + suffix)
    depFieldList.push('name' + suffix)
    empFieldList.push('shortFIO' + suffix)
    empFieldList.push('lastName' + suffix)
  })
  let eosTypeInfo
  if (employeeOnStaffType !== 'PERMANENT') {
    eosTypeInfo = UB.Repository('ubm_enum')
      .attrs(eosTypeFieldList).where('eGroup', '=', 'CDN_EMPLOYEEONSTAFFTYPE')
      .where('code', '=', employeeOnStaffType)
      .limit(1).selectSingle()
  }

  const depInfo = UB.Repository('org_staffunit').attrs(depFieldList)
    .misc({ __mip_recordhistory_all: true }).selectById(staffUnitID)
  const employeeInfo = UB.Repository('org_employee').attrs(empFieldList).selectById(employeeID)
  if (!employeeInfo) return // employee can be deleted - issue unitybase/ubjs#46
  tabNo = tabNo && String(tabNo).trim() ? tabNo + ' - ' : ''
  // property "caption" must be deleted to prevent error on insert/update multilingual attribute
  delete execParams.caption
  supportedLangs.forEach(function (lang) {
    const suffix = '_' + lang + '^'
    // [unitybase/ubjs#14] - in case `shortFIO` is not defined use the `lastName` (it's not null attribute)
    const empName = employeeInfo['shortFIO' + suffix] || employeeInfo['lastName' + suffix]
    let depName = depInfo['parentID.caption' + suffix] + ' '
    let staffUnitName = depInfo['name' + suffix]
    let eosType = ''
    if (eosTypeInfo) {
      eosType = ' - (' + eosTypeInfo['name' + suffix] + ')'
    }
    let employeeOnStaffCaption = `${empName} (${tabNo}${depName})${eosType}`
    if (employeeOnStaffCaption.length + staffUnitName.length > 1023) {
      const subStringLength = (employeeOnStaffCaption.length + staffUnitName.length) - 1023
      const depNameL = depName.length - subStringLength
      if (depNameL > 200) {
        depName = depName.substring(0, depNameL - 5) + '... '
      } else {
        let employeeOnStaffCaptionL = employeeOnStaffCaption.length - depName.length
        depName = depName.substring(0, 200) + '... ' // 204
        employeeOnStaffCaptionL = employeeOnStaffCaptionL + depName.length + staffUnitName.length
        staffUnitName = staffUnitName.substring(0, staffUnitName.length - (employeeOnStaffCaptionL - 1023) - 4) + '...'
      }
    }
    employeeOnStaffCaption = `${empName} (${tabNo}${depName}${staffUnitName})${eosType}`
    execParams['caption' + suffix] = employeeOnStaffCaption
  })
  return true
}

/**
 * Deletes all pending actions for the given employeeonstaff ID.
 *
 * @param {number} emponstaffID
 */
function deletePendingAction (emponstaffID) {
  const pendingStore = UB.DataStore('org_employeeonstaff_pending')
  const pendingActionIDs = UB.Repository('org_employeeonstaff_pending')
    .attrs('ID')
    .where('emponstaffID', '=', emponstaffID)
    .selectAsArrayOfValues()
  for (const ID of pendingActionIDs) {
    pendingStore.run('delete', {
      fieldList: [],
      execParams: {
        ID
      },
      __skipOptimisticLock: true
    })
  }
}

/**
 * Updates or inserts a record into the `org_employeeonstaff_pending` entity.
 *
 * @param {number} emponstaffID
 * @param {string|Date} updateDate
 * @param {string} updateReason
 */
function upsertPendingAction (emponstaffID, updateDate, updateReason) {
  const pendingStore = UB.DataStore('org_employeeonstaff_pending')
  const pendingRowID = UB.Repository('org_employeeonstaff_pending')
    .attrs('ID')
    .where('emponstaffID', '=', emponstaffID)
    .where('updateReason', '=', updateReason)
    .selectScalar()

  if (pendingRowID) {
    if (new Date(updateDate) > new Date()) {
      pendingStore.run('update', {
        fieldList: [],
        execParams: {
          ID: pendingRowID,
          emponstaffID,
          updateDate,
          updateReason
        },
        __skipOptimisticLock: true
      })
    } else {
      pendingStore.run('delete', {
        fieldList: [],
        execParams: {
          ID: pendingRowID
        },
        __skipOptimisticLock: true
      })
    }
  } else if (new Date(updateDate) > new Date()) {
    pendingStore.run('insert', {
      fieldList: [],
      execParams: {
        ID: pendingStore.generateID(),
        emponstaffID,
        updateDate,
        updateReason
      },
      __skipOptimisticLock: true
    })
  }
}