const { Task, api } = require('actionhero')
const sequelize = require('sequelize')
const haversine = require('haversine-distance')

module.exports = class AutoLocation extends Task {
  constructor () {
    super()
    this.name = 'autoLocation'
    this.description = 'Populate location based on coordinates'
    // use cronjob to schedule the task
    // npm run enqueue autoLocation
    this.frequency = 0
  }

  async run ({ form, id } = {}, worker) {
    if (!form) {
      return Promise.all(Object.values(api.forms).map(async (form) => {
        if (!form.$isForm) return

        await api.tasks.enqueue('autoLocation', { form: form.modelName }, 'default')
      }))
    }

    const records = await api.forms[form].model.findAll({
      where: id ? { id } : { autoLocationEn: null },
      limit: api.config.app.location.maxRecords,
      order: [['id', 'DESC']]
    })
    await Promise.all(records.map(async (record) => {
      const settlement = await api.models.settlement.findOne({
        order: sequelize.literal(`(latitude-${api.sequelize.sequelize.escape(record.latitude)})*(latitude-${api.sequelize.sequelize.escape(record.latitude)}) + (longitude-${api.sequelize.sequelize.escape(record.longitude)})*(longitude-${api.sequelize.sequelize.escape(record.longitude)})`)
      })
      if (settlement) {
        const dist = haversine(settlement, record)
        if (dist <= api.config.app.location.maxDistance) {
          // en is not required, so it may be null, default to empty string to prevent duplicate processing
          record.autoLocationEn = settlement.nameEn || ''
          record.autoLocationLocal = settlement.nameLocal
          record.autoLocationLang = settlement.nameLang
          await record.save()
          return
        }
      }

      // mark as empty string so we don't repeat it
      record.autoLocationEn = ''
      await record.save()
    }))
  }
}

@@ -921,24 +921,91 @@
 ecord) =%3E %7B%0A
+      if (record.latitude != null && record.longitude != null) %7B%0A  
       const 
@@ -1059,24 +1059,26 @@
 e(%7B%0A        
+  
 order: seque
@@ -1091,16 +1091,27 @@
 iteral(%60
+%0A          
 (latitud
@@ -1104,32 +1104,33 @@
       (latitude-
+(
 $%7Bapi.sequelize.
@@ -1164,16 +1164,17 @@
 itude)%7D)
+)
 *(latitu
@@ -1172,24 +1172,25 @@
 )*(latitude-
+(
 $%7Bapi.sequel
@@ -1232,10 +1232,32 @@
 e)%7D)
+)%0A           +%0A        
  
-+
  (lo
@@ -1256,32 +1256,33 @@
      (longitude-
+(
 $%7Bapi.sequelize.
@@ -1317,16 +1317,17 @@
 itude)%7D)
+)
 *(longit
@@ -1330,16 +1330,17 @@
 ngitude-
+(
 $%7Bapi.se
@@ -1387,11 +1387,25 @@
 e)%7D)
+)%0A          
 %60)%0A
+  
     
@@ -1405,24 +1405,26 @@
 %0A        %7D)%0A
+  
       if (se
@@ -1439,24 +1439,26 @@
 ) %7B%0A        
+  
 const dist =
@@ -1488,16 +1488,18 @@
 record)%0A
+  
         
@@ -1559,16 +1559,18 @@
         
+ 
+ 
 // en is
@@ -1661,32 +1661,34 @@
 ssing%0A          
+  
 record.autoLocat
@@ -1721,32 +1721,34 @@
 %7C%7C ''%0A          
+ 
+ 
 record.autoLocat
@@ -1781,32 +1781,34 @@
 Local%0A          
+  
 record.autoLocat
@@ -1837,16 +1837,18 @@
 ameLang%0A
+  
         
@@ -1879,23 +1879,37 @@
         
+  
 return%0A
+          %7D%0A
         

Fix searching settlements with negative coordinates and protect against missing coordinates