/**
 * i18n
 * 国际化
 */

layui.define('lay', function (exports) {
  'use strict';

  var lay = layui.lay;
  var hint = layui.hint();

  var MOD_NAME = 'i18n';

  // 识别预先可能定义的指定全局对象
  var GLOBAL = window.LAYUI_GLOBAL || {};

  // 简体中文
  var zhCN = {
    code: {
      copy: '复制代码',
      copied: '已复制',
      copyError: '复制失败',
      maximize: '最大化显示',
      restore: '还原显示',
      preview: '在新窗口预览'
    },
    colorpicker: {
      clear: '清除',
      confirm: '确定'
    },
    dropdown: {
      noData: '暂无数据'
    },
    flow: {
      loadMore: '加载更多',
      noMore: '没有更多了'
    },
    form: {
      select: {
        noData: '暂无数据',
        noMatch: '无匹配数据',
        placeholder: '请选择'
      },
      validateMessages: {
        required: '必填项不能为空',
        phone: '手机号格式不正确',
        email: '邮箱格式不正确',
        url: '链接格式不正确',
        number: '只能填写数字',
        date: '日期格式不正确',
        identity: '身份证号格式不正确'
      },
      verifyErrorPromptTitle: '提示'
    },
    laydate: {
      months: [
        '1月',
        '2月',
        '3月',
        '4月',
        '5月',
        '6月',
        '7月',
        '8月',
        '9月',
        '10月',
        '11月',
        '12月'
      ],
      weeks: ['日', '一', '二', '三', '四', '五', '六'],
      time: ['时', '分', '秒'],
      literal: {
        year: '年'
      },
      selectDate: '选择日期',
      selectTime: '选择时间',
      startTime: '开始时间',
      endTime: '结束时间',
      tools: {
        confirm: '确定',
        clear: '清空',
        now: '现在',
        reset: '重置'
      },
      rangeOrderPrompt: '结束时间不能早于开始时间\n请重新选择',
      invalidDatePrompt: '不在有效日期或时间范围内\n',
      formatErrorPrompt: '日期格式不合法\n必须遵循：\n{format}\n',
      autoResetPrompt: '已自动重置',
      preview: '当前选中的结果'
    },
    layer: {
      confirm: '确定',
      cancel: '取消',
      defaultTitle: '信息',
      prompt: {
        InputLengthPrompt: '最多输入 {length} 个字符'
      },
      photos: {
        noData: '没有图片',
        tools: {
          rotate: '旋转',
          scaleX: '水平变换',
          zoomIn: '放大',
          zoomOut: '缩小',
          reset: '还原',
          close: '关闭'
        },
        viewPicture: '查看原图',
        urlError: {
          prompt: '当前图片地址异常，\n是否继续查看下一张？',
          confirm: '下一张',
          cancel: '不看了'
        }
      }
    },
    laypage: {
      prev: '上一页',
      next: '下一页',
      first: '首页',
      last: '尾页',
      total: '共 {total} 条',
      pagesize: '条/页',
      goto: '到第',
      page: '页',
      confirm: '确定'
    },
    table: {
      sort: {
        asc: '升序',
        desc: '降序'
      },
      noData: '暂无数据',
      tools: {
        filter: {
          title: '筛选列'
        },
        export: {
          title: '导出',
          noDataPrompt: '当前表格无数据',
          compatPrompt: '导出功能不支持 IE，请用 Chrome 等高级浏览器导出',
          csvText: '导出 CSV 文件'
        },
        print: {
          title: '打印',
          noDataPrompt: '当前表格无数据'
        }
      },
      dataFormatError:
        '返回的数据不符合规范，正确的成功状态码应为："{statusName}": {statusCode}',
      xhrError: '请求异常，错误提示：{msg}'
    },
    transfer: {
      noData: '暂无数据',
      noMatch: '无匹配数据',
      title: ['列表一', '列表二'],
      searchPlaceholder: '关键词搜索'
    },
    tree: {
      defaultNodeName: '未命名',
      noData: '暂无数据',
      deleteNodePrompt: '确认删除"{name}"节点吗？'
    },
    upload: {
      fileType: {
        file: '文件',
        image: '图片',
        video: '视频',
        audio: '音频'
      },
      validateMessages: {
        fileExtensionError: '选择的{fileType}中包含不支持的格式',
        filesOverLengthLimit: '同时最多只能上传: {length} 个文件',
        currentFilesLength: '当前已经选择了: {length} 个文件',
        fileOverSizeLimit: '文件大小不能超过 {size}'
      },
      chooseText: '{length} 个文件'
    },
    util: {
      timeAgo: {
        days: '{days} 天前',
        hours: '{hours} 小时前',
        minutes: '{minutes} 分钟前',
        future: '未来',
        justNow: '刚刚'
      },
      toDateString: {
        // https://www.unicode.org/cldr/charts/47/supplemental/day_periods.html
        meridiem: function (hours, minutes) {
          var hm = hours * 100 + minutes;
          if (hm < 500) {
            return '凌晨';
          } else if (hm < 800) {
            return '早上';
          } else if (hm < 1200) {
            return '上午';
          } else if (hm < 1300) {
            return '中午';
          } else if (hm < 1900) {
            return '下午';
          }
          return '晚上';
        }
      }
    }
  };

  // 默认配置
  var config = lay.extend(
    {
      locale: 'zh-CN', // 全局内置语言
      messages: {
        // 全局国际化消息对象
        'zh-CN': zhCN
      }
    },
    GLOBAL.i18n
  ); // 读取全局预设配置，确保打包后的版本初始调用时机

  var OBJECT_REPLACE_REGEX = /\{(\w+)\}/g;

  /**
   * 获取对象中指定路径的值，类似于 lodash 的 _.get 方法（简易版）
   * @param {Record<string, any>} obj - 要查找的对象
   * @param {string} path - 要查找的路径，支持类似 'a[0].b.c' 的格式
   * @param {any} defaultValue - 若未找到对应值时返回的默认值
   * @returns {any} - 找到的值或默认值
   */
  function get(obj, path, defaultValue) {
    // 'a[0].b.c' ==> ['a', '0', 'b', 'c']
    var casePath = path.replace(/\[(\d+)\]/g, '.$1').split('.');
    var result = obj;

    for (var i = 0; i < casePath.length; i++) {
      result = result && result[casePath[i]];
      if (result === null || result === undefined) {
        return defaultValue;
      }
    }

    return result;
  }

  /**
   * 为纯函数创建具有缓存功能的版本，类似于 lodash 的 _.memoize 方法（简易版）
   * @template T
   * @param {(key: string, ...args) => T} fn - 需要缓存的函数，第一个参数为键
   * @returns {{(key: string, ...args): T, cleanup: () => void}} - 带有缓存的函数
   */
  function memoize(fn) {
    /** @type Record<string, T> */
    var cache = Object.create(null);

    function cachedFn(key) {
      var hit = cache[key];
      return hit || (cache[key] = fn.apply(cache, arguments));
    }

    cachedFn.cleanup = function () {
      cache = Object.create(null);
    };
    return cachedFn;
  }

  /**
   * 对传入的值进行转义处理
   * 若值为字符串，直接进行转义；若为函数，对函数返回的字符串进行转义；若为数组，对数组中的字符串元素进行转义
   * @param {any} value - 需要进行转义处理的值
   * @returns {any} - 转义后的结果
   */
  function escape(value) {
    if (typeof value === 'string') {
      value = lay.escape(value);
    } else if (typeof value === 'function') {
      var origFn = value;
      value = function () {
        var val = origFn.apply(this, arguments);
        return typeof val === 'string' ? lay.escape(val) : val;
      };
    } else if (layui.type(value) === 'array') {
      value = value.map(function (v) {
        return typeof v === 'string' ? lay.escape(v) : v;
      });
    }

    return value;
  }

  function isDef(value) {
    return value !== null && value !== undefined;
  }

  var resolveValue = memoize(function (path, obj, defaultValue) {
    var pathParts = path.split(':');
    var locale = pathParts[0];

    path = pathParts[1];

    var value = get(obj, path, defaultValue);

    if (layui.cache.debug) {
      var isFallback = defaultValue === value || value === path;
      var isNotFound = !isDef(value) || isFallback;
      if (isNotFound) {
        hint.errorOnce(
          "Not found '" + path + "' key in '" + locale + "' locale messages.",
          'warn'
        );
      }
      if (isFallback) {
        hint.errorOnce(
          "Fallback to default message for key: '" + path + "'",
          'warn'
        );
      }
    }

    return isDef(value) ? value : path;
  });

  var i18n = {
    config: config,
    set: function (options) {
      lay.extend(config, options);
      resolveValue.cleanup();
    }
  };

  /**
   * 根据给定的键从国际化消息中获取翻译后的内容
   * 未文档化的私有方法，仅限内部使用
   *
   * @internal
   * @param {string} keypath 要翻译的键路径
   * @param {Record<string, any> | any[]} [parameters] 可选的占位符替换参数：
   * - 对象形式：用于替换 `{key}` 形式的占位符；
   * - 数组形式：用于替换 `{0}`, `{1}` 等占位符；
   * @param {{locale: string, default: string}} [options] 翻译选项
   * @returns {string} 翻译后的文本
   *
   * @example 使用对象替换命名占位符
   * message: {
   *   hello: '{msg} world'
   * }
   * i18n.$t('message.hello', { msg: 'Hello' })
   *
   * @example 使用数组替换索引占位符
   * message: {
   *   hello: '{0} world'
   * }
   * i18n.$t('message.hello', ['Hello'])
   */
  i18n.translation = function (keypath, parameters, options) {
    var locale = (options && options.locale) || config.locale;
    var i18nMessages = config.messages[locale];
    var namespace = locale + ':';
    var hasDefault = options && lay.hasOwn(options, 'default');
    var fallbackMessage = hasDefault ? options.default : undefined;

    if (!i18nMessages && !hasDefault) {
      hint.errorOnce(
        "Locale '" +
          locale +
          "' not found. Please add i18n messages for this locale first.",
        'warn'
      );
    }

    var result = resolveValue(
      namespace + keypath,
      i18nMessages,
      fallbackMessage
    );

    // 替换占位符
    if (typeof result === 'string' && parameters) {
      // 第二个参数为对象或数组，替换占位符 {key} 或 {0}, {1}...
      result = result.replace(OBJECT_REPLACE_REGEX, function (match, key) {
        return parameters[key] !== undefined ? parameters[key] : match;
      });
    }

    return escape(result);
  };

  /**
   * i18n.translation 的别名，用于简化代码书写，未文档化仅限内部使用
   */
  i18n.$t = i18n.translation;

  exports(MOD_NAME, i18n);
});
