import { Readable, Writable } from "@embra/reactivity";
import { FC, PropsWithChildren } from "react";

//#region src/detect-lang.d.ts
/**
 * Get browser/nodejs language
 *
 * @returns BCP 47 tags of the browser/nodejs language
 */
declare function detectLang(): string;
/**
 * Get browser/nodejs language that matches the given language tags
 *
 * @param langs The language tags to match (BCP 47 tags and sub-tags are supported)
 * @returns The first language tag that matches the browser/nodejs language, or `null` if no match
 *
 * @example
 * ```js
 * detectLang(["en", "zh-CN"]) || "zh-TW"
 * ```
 */
declare function detectLang<T extends string>(langs: readonly T[]): T | null;
declare function detectLang(langs: readonly string[]): string | null;
//#endregion
//#region src/interface.d.ts
type LocaleLang = string;
type LocaleLangObservable = Readable<LocaleLang>;
type Locale = {
  readonly [key: string]: string | Locale;
};
type Locales = {
  readonly [lang: LocaleLang]: Locale;
};
type TFunctionArgs = {
  readonly [key: string | number]: any;
  /**
   * Modifier matching.
   * @see {@link https://github.com/embrajs/i18n#modifier-matching}
   */
  readonly "@"?: string | number;
};
/**
 * @param keyPath Dot-separated key path to the locale message, e.g. `"a.b.c"`
 * @param args Optional arguments for interpolation
 * @returns locale message or `keyPath` if not found
 */
type TFunction = (keyPath: string, args?: TFunctionArgs) => string;
type TFunctionObservable = Readable<TFunction>;
type LocaleFetcher = (lang: LocaleLang) => Promise<Locale> | Locale;
//#endregion
//#region src/i18n.d.ts
interface I18nOptions {
  /** Fetch locale of the specified lang. */
  fetcher?: LocaleFetcher;
  /** Fallback language if the current language doesn't have the requested key. */
  fallback?: LocaleLang;
}
declare class I18n {
  /** Fetch locale of `initialLang` and return an I18n instance with the locale. */
  static preload(initialLang: LocaleLang, fetcher: LocaleFetcher, options?: Omit<I18nOptions, "fetcher">): Promise<I18n>;
  /** A {@link Readable} of current lang. */
  readonly lang$: Readable<LocaleLang>;
  /** Current lang. */
  get lang(): LocaleLang;
  /** A {@link Readable} of current translate function. */
  readonly t$: Readable<TFunction>;
  /** Translation function that uses the current `t$` function. */
  readonly t: TFunction;
  /** Fetch locale of the specified lang. */
  fetcher?: LocaleFetcher;
  /** A {@link Writable} of all loaded locales. */
  readonly locales$: Writable<Locales>;
  /** All loaded locales. */
  get locales(): Locales;
  /** A {@link Readable} of current locale. */
  readonly locale$: Readable<Locale>;
  /** Current locale */
  get locale(): Locale;
  constructor(initialLang: LocaleLang, locales: Locales, options?: I18nOptions);
  /**
   * Change language.
   *
   * @returns — a promise that resolves when the new locale is fetched.
   */
  switchLang(lang: LocaleLang): Promise<void>;
  /**
   * @returns — boolean indicating whether a message with the specified key in current language exists or not.
   */
  hasKey(key: string): boolean;
  /**
   * Add a locale to the locales.
   *
   * Use `i18n.locales$.set()` for more control.
   */
  addLocale(lang: LocaleLang, locale: Locale): void;
  dispose(): void;
}
//#endregion
//#region src/react/i18n-context.d.ts
interface I18nProviderProps {
  i18n: I18n;
}
/**
 * Provides the I18n instance to the rest of the app.
 *
 * @example
 * ```tsx
 * <I18nProvider i18n={i18n}>
 *   <App />
 * </I18nProvider>
 */
declare const I18nProvider: FC<PropsWithChildren<I18nProviderProps>>;
interface UseTranslate {
  (): TFunction;
  (optional?: false): TFunction;
  (optional?: boolean): TFunction | undefined;
}
/**
 * @returns A {@link TFunction} that translates the key from the nearest {@link I18nProvider} and fallbacks outwards.
 * If no {@link I18nProvider} found, throws an error unless `optional` is true.
 */
declare const useTranslate: UseTranslate;
interface UseI18n {
  (): I18n;
  (optional?: false): I18n;
  (optional?: boolean): I18n | undefined;
}
/**
 * @returns The {@link I18n} instance from the nearest {@link I18nProvider}.
 * If no {@link I18nProvider} found, throws an error unless `optional` is true.
 */
declare const useI18n: UseI18n;
interface UseLang {
  (): LocaleLang;
  (optional?: false): LocaleLang;
  (optional?: boolean): LocaleLang | undefined;
}
/**
 * @returns The {@link LocaleLang} from the nearest {@link I18nProvider}.
 * If no {@link I18nProvider} found, throws an error unless `optional` is true.
 */
declare const useLang: UseLang;
//#endregion
//#region src/react/trans.d.ts
interface TProps {
  /** Locale translation message */
  message: string;
}
/**
 * Insert React elements to the translation message.
 *
 * @example
 * ```tsx
 * <Trans message="a{{b}}c{{d}}e">
 *   <h1 data-t-slot="b">B</h1>
 *   <p data-t-slot="d">D</p>
 * </Trans>
 * ```
 *  ↓
 * ```tsx
 * <>
 *   a<h1 data-t-slot="b">B</h1>c<p data-t-slot="d">D</p>e
 * <>
 * ```
 *
 * `data-t-slot` can be ignored if there is only one placeholder.
 *
 * @example
 * ```tsx
 * <Trans message="a{{b}}c">
 *   <h1>B</h1>
 * </Trans>
 * ```
 *  ↓
 * ```tsx
 * <>
 *   a<h1>B</h1>c
 * </>
 * ```
 */
declare const Trans: FC<PropsWithChildren<TProps>>;
//#endregion
export { I18nProvider, I18nProviderProps, TProps, Trans, UseI18n, UseLang, UseTranslate, useI18n, useLang, useTranslate };