import type { App } from 'vue';

import type { LocaleSetupOptions } from './typing';

const messages: Record<string, any> = {};
const coreModules = import.meta.glob('./langs/zh-CN/*.json', { eager: true });

function isRecord(value: unknown): value is Record<string, any> {
  return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}

function normalizeModule(module: unknown) {
  return isRecord(module) && 'default' in module ? module.default : module;
}

function mergeDeep(target: Record<string, any>, source?: Record<string, any>) {
  if (!source) {
    return target;
  }
  for (const [key, value] of Object.entries(source)) {
    if (isRecord(value) && isRecord(target[key])) {
      mergeDeep(target[key], value);
    } else {
      target[key] = value;
    }
  }
  return target;
}

function toLocaleMessages(
  modules: Record<string, unknown>,
  regexp = /\.\/langs\/zh-CN\/(.*)\.json$/,
) {
  const result: Record<string, any> = {};
  for (const [path, module] of Object.entries(modules)) {
    const fileName = path.match(regexp)?.[1];
    if (!fileName) {
      continue;
    }
    result[fileName] = normalizeModule(module);
  }
  return result;
}

function mergeLocaleMessages(message: Record<string, any>) {
  mergeDeep(messages, message);
}

mergeLocaleMessages(toLocaleMessages(coreModules));

function getValueByPath(path: string) {
  if (!path) {
    return path;
  }
  let current: unknown = messages;
  for (const key of path.split('.')) {
    current = isRecord(current) ? current[key] : undefined;
  }
  return current;
}

function $te(key: string) {
  return getValueByPath(key) !== undefined;
}

function formatMessage(
  message: string,
  params?: Array<unknown> | Record<string, unknown>,
) {
  if (!params) {
    return message;
  }

  return message.replaceAll(/\{(\w+)\}/g, (placeholder, key: string) => {
    const value = Array.isArray(params) ? params[Number(key)] : params[key];
    return value === undefined || value === null ? placeholder : String(value);
  });
}

function $t(
  key?: null | string,
  params?: Array<unknown> | Record<string, unknown>,
) {
  if (!key) {
    return '';
  }
  const value = getValueByPath(key);
  return typeof value === 'string' ? formatMessage(value, params) : key;
}

function setLocale() {
  document?.querySelector('html')?.setAttribute('lang', 'zh-CN');
}

async function setupLocale(app: App, options: LocaleSetupOptions = {}) {
  void app;
  void options;
  setLocale();
}

export {
  $t,
  $te,
  mergeLocaleMessages,
  setupLocale,
};
