import { Model } from 'objection'
import { find } from 'lodash-es'
import { stat, readFile } from 'node:fs/promises'
import path from 'node:path'
import { DateTime } from 'luxon'

/**
 * Locales model
 */
export class Locale extends Model {
  static get tableName() { return 'locales' }
  static get idColumn() { return 'code' }

  static get jsonSchema () {
    return {
      type: 'object',
      required: ['code', 'name'],

      properties: {
        code: {type: 'string'},
        isRTL: {type: 'boolean', default: false},
        name: {type: 'string'},
        nativeName: {type: 'string'},
        createdAt: {type: 'string'},
        updatedAt: {type: 'string'},
        completeness: {type: 'integer'}
      }
    }
  }

  static get jsonAttributes() {
    return ['strings']
  }

  $beforeUpdate() {
    this.updatedAt = new Date().toISOString()
  }
  $beforeInsert() {
    this.createdAt = new Date().toISOString()
    this.updatedAt = new Date().toISOString()
  }

  static async refreshFromDisk ({ force = false } = {}) {
    try {
      const localesMeta = (await import(`../locales/metadata.mjs`)).default
      WIKI.logger.info(`Found ${localesMeta.languages.length} locales: [ OK ]`)

      const dbLocales = await WIKI.db.locales.query().select('code', 'updatedAt')

      let localFilesSkipped = 0
      for (const lang of localesMeta.languages) {
        // -> Build filename
        const langFilenameParts = [lang.language]
        if (lang.region) {
          langFilenameParts.push(lang.region)
        }
        if (lang.script) {
          langFilenameParts.push(lang.script)
        }
        const langFilename = langFilenameParts.join('-')

        // -> Get DB version
        const dbLang = find(dbLocales, ['code', langFilename])

        // -> Get File version
        const flPath = path.join(WIKI.SERVERPATH, `locales/${langFilename}.json`)
        try {
          const flStat = await stat(flPath)
          const flUpdatedAt = DateTime.fromJSDate(flStat.mtime)

          // -> Load strings
          if (!dbLang || DateTime.fromJSDate(dbLang.updatedAt) < flUpdatedAt || force) {
            WIKI.logger.debug(`Loading locale ${langFilename} into DB...`)
            const flStrings = JSON.parse(await readFile(flPath, 'utf8'))
            await WIKI.db.locales.query().insert({
              code: langFilename,
              name: lang.name,
              nativeName: lang.localizedName,
              language: lang.language,
              region: lang.region,
              script: lang.script,
              isRTL: lang.isRtl,
              strings: flStrings
            }).onConflict('code').merge(['strings', 'updatedAt'])
          } else {
            WIKI.logger.debug(`Locale ${langFilename} is newer in the DB. Skipping disk version. [ OK ]`)
          }
        } catch (err) {
          localFilesSkipped++
          WIKI.logger.debug(`Locale ${langFilename} not found on disk. Missing strings file. [ SKIPPED ]`)
        }
      }
      if (localFilesSkipped > 0) {
        WIKI.logger.info(`${localFilesSkipped} locales were defined in the metadata file but not found on disk. [ SKIPPED ]`)
      }
    } catch (err) {
      WIKI.logger.warn(`Failed to load locales from disk: [ FAILED ]`)
      WIKI.logger.warn(err)
      return false
    }
  }

  static async getLocales ({ cache = true } = {}) {
    if (!WIKI.cache.has('locales') || !cache) {
      const locales = await WIKI.db.locales.query().select('code', 'isRTL', 'language', 'name', 'nativeName', 'createdAt', 'updatedAt', 'completeness')
      WIKI.cache.set('locales', locales)
      for (const locale of locales) {
        WIKI.cache.set(`locale:${locale.code}`, locale)
      }
    }
    return WIKI.cache.get('locales')
  }

  static async getStrings (locale) {
    const { strings } = await WIKI.db.locales.query().findOne('code', locale).column('strings')
    return strings
  }

  static async reloadCache () {
    await WIKI.db.locales.getLocales({ cache: false })
  }

  static async getNavLocales({ cache = false } = {}) {
    return []
    // if (!WIKI.config.lang.namespacing) {
    //   return []
    // }

    // if (cache) {
    //   const navLocalesCached = await WIKI.cache.get('nav:locales')
    //   if (navLocalesCached) {
    //     return navLocalesCached
    //   }
    // }
    // const navLocales = await WIKI.db.locales.query().select('code', 'nativeName AS name').whereIn('code', WIKI.config.lang.namespaces).orderBy('code')
    // if (navLocales) {
    //   if (cache) {
    //     await WIKI.cache.set('nav:locales', navLocales, 300)
    //   }
    //   return navLocales
    // } else {
    //   WIKI.logger.warn('Site Locales for navigation are missing or corrupted.')
    //   return []
    // }
  }
}
