/**
 * 国际化模块
 */

 import { Singleton, Container, Inject } from "typescript-ioc";
 import { Context, logger } from "mslib"
 import { TyGlobalApiClient, Token } from "./TyGlobalApi";
 import { redisClient } from "./Redis";
 import Contants, { IS_PARK, IS_PROD } from "./Contants";
 import { retry } from "./Decorators";
 import { GlobalConfig } from "./Config";
 
 /**
  * 国际化服务类
  */
 @Singleton
 export class GlobalService {
     @Inject
     tyGlobalApiClient: TyGlobalApiClient;
 
     /**
      * 获取语言包
      */
     async getLanguagePacks(args: { token: Token, language?: string }): Promise<{
         [lang: string]: { key: string, value: string }[]
     }> {
         let apiResponse = await this.tyGlobalApiClient.get({
             token: args.token,
             type: 1
         });
 
         let packs = {};
         packs['zh_CN'] = [];
         let cn_pack = {};
 
         /**
          统一接口返回的语言包数据是平铺的格式:{language,key,value,cn},且每条条目中都包含他的中文翻译
          */
         for (const item of apiResponse.data?.data) {
             if (!packs[item.language]) packs[item.language] = [];
 
             packs[item.language].push({ key: item.key, value: item.value });
             if (!Reflect.has(cn_pack, item.key)) cn_pack[item.key] = item.cn;
         }
 
         for (const key in cn_pack) {
             packs['zh_CN'].push({ key: key, value: cn_pack[key] });
         }
 
         if (Contants.IS_LOCAL_DEBUG) {
             packs['en_US'].push({ key: 'config_alert_offlineAlertThresholdTime2', value: '1111111111111111111111111111111' });
             packs['zh_CN'].push({ key: 'config_alert_offlineAlertThresholdTime2', value: '这是中文翻译后的结果' });
         }
 
         return packs;
     }
 }
 
 /**
  * 默认语种：zh_CN
  */
 export let DEFAULT_LANG = 'zh_CN';
 
 /**
  * i18n国际化实例
  * 
  * 模块被加载时，从ioc读取配置config.global并自动创建该实例+初始化，如果未配置则为空
  * 
  * 当config.global.mode=PARK时，从场端redis加载语言包
  * 
  * 当config.global.mode=CLOUD时，从云端redis加载语言包
  * 
  * 基本用法：
  * 
  * i18n.__('(主相机)') //根据默认语种进行翻译
  * 
  * i18n.__('Hello %s', 'Keytop') //根据默认语种翻译短语，带占位符%s
  * 
  * i18n.__('Hello {0}', ['Keytop']) //根据默认语种翻译短语，带占位符{0}
  * 
  * i18n.__('Hello {name}', { name: 'Keytop' }) //根据默认语种翻译短语，带属性占位符{name}
  * 
  * i18n.__({ phrase: 'Hello %s', locale: 'en_US' }, 'Keytop1') 
  * 
  * i18n.__({ phrase: 'Hello {0}', locale: 'en_US' }, ['Keytop1'])
  * 
  * i18n.__({ phrase: 'Hello {name}', locale: 'en_US' }, { name: 'Keytop1' })
  * 
  * https://www.npmjs.com/package/i18n
  */
 export let i18n = null;
 
 let config: GlobalConfig = Container.getValue('config.global');
 
 if (config?.enabled === true) {
     const { I18n } = require('i18n');
     i18n = new I18n();
 
     init_i18n();
 
     // setInterval(async () => {
     //     try {
     //         await configure_i18n();
     //         logger.info('定时刷新i18n配置成功');
     //     } catch (error) {
     //         logger.error('定时刷新i18n配置失败', error);
     //     }
     // }, Contants.IS_LOCAL_DEBUG ? 1000 * 60 : 1000 * 60 * 10);
 }
 
 async function init_i18n() {
     try {
         await retry(async () => {
             if (Contants.IS_PARK) {
                 await configure_i18n_park();
             } else {
                 await configure_i18n_cloud();
             }
 
             logger.info('i18n配置成功');
         }, 3, 500, {
             errorHandler: (error, retryCountLeft) => {
                 logger.error(`i18n配置失败(${retryCountLeft})`, error);
             }
         });
     } catch (error) {
         logger.error('i18n配置失败', error);
     }
 }
 
 async function configure_i18n_cloud() {
     let packs = await redisClient.hgetall('translation_1102011');
     let staticCatalog = {};
 
     for (const key in packs) {
         try {
             let pack = {};
 
             JSON.parse(packs[key]).forEach(s => {
                 pack[s.key] = s.value;
             });
 
             staticCatalog[key] = pack;
         } catch (error) {
             logger.error(`加载云端redis语言包失败,lang:${key}`, error);
         }
     }
 
     logger.info(`加载云端redis语言包成功,lang:${Reflect.ownKeys(staticCatalog).join(',')}`);
 
     i18n.configure({
         locales: Reflect.ownKeys(staticCatalog),
         staticCatalog: staticCatalog,
         mustacheConfig: {
             tags: ['{', '}'],
             disable: false
         },
         logDebugFn: function (msg) {
             logger.debug(msg);
         },
         logWarnFn: function (msg) {
             // logger.warn(msg);
         },
         logErrorFn: function (msg) {
             logger.error(msg);
         },
         missingKeyFn: function (locale, value) {
             return value;
         },
     });
 }
 
 async function configure_i18n_park() {
     let staticCatalog = {};
 
     {
         let fields: string[] = await redisClient.hkeys('t_realtime_data');
         let lang_fields = fields.filter(s => s.startsWith(`translation_1102011`))
 
         for (const field of lang_fields) {
             const [, lang] = field.split(':');
             let current_lang = lang.substring(0, lang.lastIndexOf('_'));
             if (!staticCatalog[current_lang]) staticCatalog[current_lang] = {};
 
             let json = await redisClient.hget('t_realtime_data', field);
 
             JSON.parse(json).forEach(s => {
                 staticCatalog[current_lang][s.key] = s.value;
             });
         }
     }
 
     logger.info(`加载场端redis语言包成功,lang:${Reflect.ownKeys(staticCatalog).join(',')}`);
 
     i18n.configure({
         // defaultLocale: locale,
         locales: Reflect.ownKeys(staticCatalog),
         staticCatalog: staticCatalog,
         mustacheConfig: {
             tags: ['{', '}'],
             disable: false
         },
         logDebugFn: function (msg) {
             logger.debug(msg);
         },
         logWarnFn: function (msg) {
             // logger.warn(msg);
         },
         logErrorFn: function (msg) {
             logger.error(msg);
         },
         missingKeyFn: function (locale, value) {
             return value;
         },
     });
 }
 
 let $regExp = /\$#{{(.+?)\}}/g;
 
 /**
  * 翻译数据，只翻译包含$#{{xxx}}的字符串
  * 
  * @param data 翻译的数据，可以是任意对象
  * @param lang 目标语种,如果i18n已配置默认语种,不用传
  */
 function $translate(data: any, lang?: string) {
     if (typeof data === 'object') {
         for (const key in data) {
             if (typeof data[key] === 'object') {
                 $translate(data[key], lang);
             } else {
                 if (typeof data[key] === 'string' && $regExp.test(data[key])) {
                     data[key] = data[key].replace($regExp, (s) => {
                         return lang ? i18n.__({ phrase: s.substring(4, s.length - 2), locale: lang }) : i18n.__(s.substring(4, s.length - 2));
                     });
                 }
             }
         }
 
         return data;
     } else {
         if (typeof data === 'string' && $regExp.test(data)) {
             return data.replace($regExp, (s) => {
                 return lang ? i18n.__({ phrase: s.substring(4, s.length - 2), locale: lang }) : i18n.__(s.substring(4, s.length - 2));
             });
         } else {
             return data;
         }
     }
 }
 
 /**
  * 翻译数据
  * 
  * @param data 翻译的数据，可以是任意对象
  * @param lang 目标语种,如果i18n已配置默认语种,不用传
  */
 function translate(data: any, lang?: string) {
     if (typeof data === 'object') {
         for (const key in data) {
             if (typeof data[key] === 'object') {
                 translate(data[key], lang);
             } else {
                 if (typeof data[key] === 'string') {
                     data[key] = lang ? i18n.__({ phrase: data[key], locale: lang }) : i18n.__(data[key]);
                 }
             }
         }
         return data;
     } else {
         if (typeof data === 'string') {
             return lang ? i18n.__({ phrase: data, locale: lang }) : i18n.__(data);
         } else {
             return data;
         }
     }
 }
 
 /**
  * 获取车场主语言
  * 
  * 1.云端从redis取
  * 
  * 2.场端从sqlite取
  */
 export async function getParkLang(parkId: any) {
     if (!Contants.IS_PARK) {
         return redisClient.get(`lang-{{${parkId}}}`);
     } else {
         let lang;
 
         const knexInstance = require('knex')({
             client: 'sqlite3',
             connection: {
                 filename: "/home/keytop/data/lotconfig.db"
             }
         });
 
         let configs = await knexInstance('t_config').where({ session: 'charge', name: 'countryAndLanguage' });
         if (configs && configs.length > 0 && configs[0].value) lang = configs[0]?.value;
 
         return lang;
     }
 }
 
 /**
  * 获取语种
  * 
  * 优先级：请求头 > redis(云端)/sqlite(场端) > zh_CN
  * @param parkId 
  */
 export async function getLang(parkId?: any) {
     let lang = null;
     let headers = Context.getRequestHeaders();
     lang = headers?.language;
 
     try {
         if (!lang && IS_PARK && parkId) {
             lang = await getParkLang(parkId);
             if (!IS_PROD) logger.info(`读取车场主语言成功,${lang || '未设置'}`);
         }
     } catch (error) {
         logger.error(error);
     }
 
     return lang || DEFAULT_LANG;
 }
 
 /**
  * 使用i18n对任意类型的对象中的所有字符串进行翻译
  * 
  * 语种优先级：请求头 > 车场主语言 > zh_CN
  * @param data 翻译的数据，可以是任意对象
  * @param parkId 车场id,用来获取车场主语言
  */
 export async function t(data: any, parkId?: any) {
     if (!data) return data;
 
     let lang = await getLang(parkId);
     return translate(data, lang);
 }
 
 /**
  * 使用i18n对任意类型的对象中的所有包含$#{{xxx}}的字符串进行翻译
  * 
  * 语种优先级：请求头 > 车场主语言 > zh_CN
  * @param data 翻译的数据，可以是任意对象
  * @param parkId 车场id,用来获取车场主语言
  */
 export async function $t(data: any, parkId?: any) {
     if (!data) return data;
 
     let lang = await getLang(parkId);
     return $translate(data, lang);
 }