import { cookies, headers } from "next/headers";
import { createInstance, i18n, LanguageDetectorAsyncModule } from "i18next";
import resourcesToBackend from "i18next-resources-to-backend";
import { getServerSession } from "next-auth";
import { authOptions } from "@/config/authConfig";
import I18nClientProvider from "./I18nClientProvider";
import universalLanguageDetect from "@unly/universal-language-detector";

const FALLBACK_LANG = "zh";
const SUPPORTED_LANGUAGES = ["zh"];

export const detectLanguage = async (): Promise<string> => {
  // Logic to get language preference from cookies/headers/session
  const cookiesList = cookies();
  const cookiesObj = cookiesList
    .getAll()
    .reduce<{ [name: string]: string }>(
      (acc, cookie) => ({ ...acc, [cookie.name]: cookie.value }),
      {},
    );
  const headersList = headers();
  console.time("[i18n] detectLanguage total");
  console.time("[i18n] getServerSession");
  const session = await getServerSession(authOptions);
  console.timeEnd("[i18n] getServerSession");
  console.time("[i18n] universalLanguageDetect");
  const lang = universalLanguageDetect({
    supportedLanguages: SUPPORTED_LANGUAGES,
    fallbackLanguage: FALLBACK_LANG,
    acceptLanguageHeader: headersList.get("accept-language") || undefined,
    serverCookies: cookiesObj,
  });
  console.timeEnd("[i18n] universalLanguageDetect");
  console.timeEnd("[i18n] detectLanguage total");
  return lang;
};

const languageDetector: LanguageDetectorAsyncModule = {
  type: "languageDetector",
  detect: detectLanguage,
  async: true,
};

const initI18next = async (namespaces: string[]): Promise<i18n> => {
  const label = `[i18n] initI18next ns=${namespaces.join(",")}`;
  console.time(label);
  const i18nInstance = createInstance();
  await i18nInstance
    .use(languageDetector)
    .use(
      resourcesToBackend((language: string, namespace: string) => {
        return import(`./${language}/${namespace}.json`);
      }),
    )
    .init({
      fallbackLng: "en",
      interpolation: {
        escapeValue: false,
      },
      ns: namespaces,
    });
  return i18nInstance as i18n;
};

export const getServerI18n = async (...namespaces: string[]) => {
  return initI18next(namespaces);
};

interface Props {
  children: React.ReactNode;
  namespaces: string[];
}

// Provides the resources for the client
export const I18nProvider: React.FC<Props> = async ({
  children,
  namespaces,
}) => {
  const i18n = await getServerI18n(...namespaces);
  const language = i18n.language;
  const resources = namespaces.reduce<{ [ns: string]: any }>(
    (acc, ns) => ({
      ...acc,
      [ns]: i18n.getResourceBundle(language, ns),
    }),
    {},
  );

  return (
    <I18nClientProvider
      language={language}
      resources={resources}
      namespaces={namespaces}
    >
      {children}
    </I18nClientProvider>
  );
};
