/**
 * Клиент для Localization Service.
 * Получает locale на основе геопозиции (через geo-device-service) и переводы.
 */

import { fetchContextWithGeolocation } from './geoDevice';
import { localeFromCountryCode } from './localization/countryToLocale';

const LOCALE_API = '/api/locale';
const TRANSLATIONS_API = '/api/translations';

export interface LocalizationContext {
  locale: string;
  language: string;
  region: string | null;
  countryCode: string | null;
  timezone: string | null;
  source: 'geo' | 'accept-language' | 'client' | 'fallback';
}

const collectClientData = () => {
  if (typeof window === 'undefined') return {};
  const nav = navigator;
  return {
    client: {
      language: nav.language,
      languages: nav.languages ? [...nav.languages] : undefined,
    },
  };
};

/**
 * Получить locale (серверный вызов — без client data).
 */
export async function fetchLocale(): Promise<LocalizationContext> {
  const res = await fetch(LOCALE_API);
  if (!res.ok) throw new Error('Failed to fetch locale');
  return res.json();
}

/**
 * Получить locale с данными клиента (браузер language).
 */
export async function fetchLocaleWithClient(): Promise<LocalizationContext> {
  const clientData = collectClientData();
  const res = await fetch(LOCALE_API, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(clientData),
  });
  if (!res.ok) throw new Error('Failed to fetch locale');
  return res.json();
}

/** IP-провайдеры возвращают country_code — fallback когда geo-device недоступен */
async function fetchCountryFromIp(): Promise<string | null> {
  const providers: Array<{
    url: string;
    getCountry: (d: Record<string, unknown>) => string | null;
  }> = [
    {
      url: 'https://get.geojs.io/v1/ip/geo.json',
      getCountry: (d) => {
        const cc = d.country_code ?? d.country;
        return typeof cc === 'string' ? cc.toUpperCase() : null;
      },
    },
    {
      url: 'https://ipwhois.app/json/',
      getCountry: (d) => {
        const cc = d.country_code ?? d.country;
        return typeof cc === 'string' ? cc.toUpperCase() : null;
      },
    },
  ];
  for (const p of providers) {
    try {
      const res = await fetch(p.url);
      const d = (await res.json()) as Record<string, unknown>;
      const country = p.getCountry(d);
      if (country) return country;
    } catch {
      /* следующий провайдер */
    }
  }
  return null;
}

/**
 * Получить locale с приоритетом geo-context (тот же источник, что у виджета погоды).
 * Если geo-context вернёт countryCode — используем его.
 * Иначе — fallback по IP (geojs, ipwhois), затем — localization service.
 */
export async function fetchLocaleWithGeoFirst(): Promise<LocalizationContext> {
  try {
    const ctx = await fetchContextWithGeolocation();
    const cc = ctx.geo?.countryCode;
    if (cc) {
      const locale = localeFromCountryCode(cc);
      return {
        locale,
        language: locale,
        region: ctx.geo?.region ?? null,
        countryCode: cc,
        timezone: ctx.geo?.timezone ?? null,
        source: 'geo',
      };
    }
  } catch {
    /* geo-context недоступен */
  }
  try {
    const countryCode = await fetchCountryFromIp();
    if (countryCode) {
      const locale = localeFromCountryCode(countryCode);
      return {
        locale,
        language: locale,
        region: null,
        countryCode,
        timezone: null,
        source: 'geo',
      };
    }
  } catch {
    /* IP fallback недоступен */
  }
  try {
    return await fetchLocaleWithClient();
  } catch {
    const nav =
      typeof navigator !== 'undefined' ? navigator.language : undefined;
    const fallback = nav ? nav.split('-')[0].toLowerCase() : 'en';
    return {
      locale: fallback,
      language: fallback,
      region: null,
      countryCode: null,
      timezone: null,
      source: 'fallback',
    };
  }
}

import {
  getEmbeddedTranslations,
  translationLocaleFor,
} from './localization/embeddedTranslations';

/**
 * Получить переводы для locale.
 * При недоступности API использует встроенные переводы.
 */
export async function fetchTranslations(
  locale: string,
): Promise<Record<string, string>> {
  const fetchLocale = translationLocaleFor(locale);
  try {
    const res = await fetch(
      `${TRANSLATIONS_API}/${encodeURIComponent(fetchLocale)}`,
    );
    if (res.ok) return res.json();
  } catch {
    /* API недоступен */
  }
  return getEmbeddedTranslations(locale);
}

/**
 * Получить locale и переводы одним вызовом.
 */
export async function fetchLocalization(): Promise<{
  locale: LocalizationContext;
  translations: Record<string, string>;
}> {
  const locale = await fetchLocaleWithClient();
  const translations = await fetchTranslations(locale.locale);
  return { locale, translations };
}
