'use client';

import { createContext, useContext, useState, useEffect, useCallback, useRef, ReactNode } from 'react';
import { DEFAULT_LANGUAGE } from './config';
import { en } from './translations/en';
import { de } from './translations/de';
import { sl } from './translations/sl';
import { flattenObject } from './dynamicTranslations';
import { authFetch } from '../utils/authFetch';
import useAuthStore from '../store/authStore';
import { API_ENDPOINTS } from '../utils/api';

type LanguageEntry = {
  code: string;
  name: string;
};

type TranslationFilesPayload = {
  languages: LanguageEntry[];
  translations: Record<string, Record<string, string>>;
};

const builtInTranslations: Record<string, Record<string, unknown>> = {
  en: en as unknown as Record<string, unknown>,
  de: de as unknown as Record<string, unknown>,
  sl: sl as unknown as Record<string, unknown>,
};

const APP_LANGUAGE_STORAGE_KEY = 'pp-selected-language';

// Flat map of English keys used as canonical key list and fallback
const enFlat = flattenObject(en as unknown as Record<string, unknown>);

function normalizeLanguageValue(value: unknown): string | null {
  if (typeof value !== 'string') return null;
  const normalized = value.trim().toLowerCase();
  return normalized ? normalized : null;
}

function extractPreferredLanguage(payload: unknown): string | null {
  if (!payload || typeof payload !== 'object') return null;

  const settings = (payload as { settings?: Record<string, unknown> }).settings;
  if (!settings || typeof settings !== 'object') return null;

  return normalizeLanguageValue(
    settings.preferred_language
      ?? settings.preferredLanguage
      ?? settings.language
      ?? settings.lang,
  );
}

function getNestedValue(root: Record<string, unknown>, key: string): string | null {
  const segments = key.split('.');
  let current: unknown = root;

  for (const segment of segments) {
    if (!current || typeof current !== 'object') return null;
    current = (current as Record<string, unknown>)[segment];
  }

  return typeof current === 'string' ? current : null;
}

interface I18nContextType {
  language: string;
  setLanguage: (lang: string) => void;
  t: (key: string) => string;
  languages: LanguageEntry[];
  reloadTranslations: () => Promise<void>;
}

const I18nContext = createContext<I18nContextType | undefined>(undefined);

interface I18nProviderProps {
  children: ReactNode;
}

export function I18nProvider({ children }: I18nProviderProps) {
  const accessToken = useAuthStore((state) => state.accessToken);
  const [language, setLanguage] = useState<string>(DEFAULT_LANGUAGE);
  const [hasSyncedStoredLanguage, setHasSyncedStoredLanguage] = useState(false);
  const [hasResolvedPersistedLanguage, setHasResolvedPersistedLanguage] = useState(false);
  const lastPersistedLanguageRef = useRef<string | null>(null);
  const [translationFiles, setTranslationFiles] = useState<TranslationFilesPayload>({
    languages: [
      { code: 'en', name: 'English' },
      { code: 'de', name: 'Deutsch' },
      { code: 'sl', name: 'Slovenian' },
    ],
    translations: {
      en: enFlat,
      de: flattenObject(de as unknown as Record<string, unknown>),
      sl: flattenObject(sl as unknown as Record<string, unknown>),
    },
  });

  const reloadTranslations = useCallback(async () => {
    try {
      const response = await fetch('/api/i18n/translations', { cache: 'no-store' });
      const result = await response.json();

      if (!response.ok || !result?.ok) return;

      const languages = Array.isArray(result.languages)
        ? result.languages.filter((lang: unknown): lang is LanguageEntry => {
            if (!lang || typeof lang !== 'object') return false;
            const entry = lang as LanguageEntry;
            return typeof entry.code === 'string' && typeof entry.name === 'string';
          })
        : [];

      const translations = result.translations && typeof result.translations === 'object'
        ? result.translations as Record<string, Record<string, string>>
        : {};

      if (languages.length > 0) {
        setTranslationFiles({ languages, translations });
      }
    } catch {
      // Keep built-in fallback translations if API is unavailable.
    }
  }, []);

  useEffect(() => {
    void reloadTranslations();
  }, [reloadTranslations]);

  useEffect(() => {
    if (typeof window === 'undefined') return;

    const stored = window.localStorage.getItem(APP_LANGUAGE_STORAGE_KEY);
    if (stored && stored.trim()) {
      setLanguage((currentLanguage) => currentLanguage === stored ? currentLanguage : stored);
    }

    setHasSyncedStoredLanguage(true);
  }, []);

  useEffect(() => {
    lastPersistedLanguageRef.current = null;
  }, [accessToken]);

  useEffect(() => {
    if (translationFiles.languages.length === 0) return;
    if (translationFiles.languages.some((entry) => entry.code === language)) return;

    const fallback = translationFiles.languages.find((entry) => entry.code === DEFAULT_LANGUAGE)?.code
      ?? translationFiles.languages[0]?.code
      ?? DEFAULT_LANGUAGE;
    setLanguage(fallback);
  }, [translationFiles.languages, language]);

  useEffect(() => {
    if (!hasSyncedStoredLanguage) return;

    let cancelled = false;

    async function syncPersistedLanguage() {
      if (!accessToken) {
        setHasResolvedPersistedLanguage(true);
        return;
      }

      setHasResolvedPersistedLanguage(false);
      try {
        const response = await authFetch(API_ENDPOINTS.USER_SETTINGS, {
          method: 'GET',
          cache: 'no-store',
        });
        const result = await response.json().catch(() => null);
        const preferredLanguage = response.ok ? extractPreferredLanguage(result) : null;

        if (!cancelled && preferredLanguage) {
          lastPersistedLanguageRef.current = preferredLanguage;
          setLanguage((currentLanguage) => currentLanguage === preferredLanguage ? currentLanguage : preferredLanguage);
        }
      } catch {
        // Ignore preference sync failures and keep local state.
      } finally {
        if (!cancelled) {
          setHasResolvedPersistedLanguage(true);
        }
      }
    }

    void syncPersistedLanguage();

    return () => {
      cancelled = true;
    };
  }, [accessToken, hasSyncedStoredLanguage]);

  useEffect(() => {
    if (typeof window === 'undefined' || !hasSyncedStoredLanguage) return;

    window.localStorage.setItem(APP_LANGUAGE_STORAGE_KEY, language);
    document.documentElement.lang = language;

    if (!accessToken || !hasResolvedPersistedLanguage || lastPersistedLanguageRef.current === language) {
      return;
    }

    let cancelled = false;

    async function persistPreferredLanguage() {
      try {
        const response = await authFetch(API_ENDPOINTS.USER_SETTINGS, {
          method: 'PUT',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({ preferredLanguage: language }),
        });

        if (!cancelled && response.ok) {
          lastPersistedLanguageRef.current = language;
        }
      } catch {
        // Ignore persistence failures; localStorage remains as the client fallback.
      }
    }

    void persistPreferredLanguage();

    return () => {
      cancelled = true;
    };
  }, [accessToken, hasResolvedPersistedLanguage, hasSyncedStoredLanguage, language]);

  const t = useCallback((key: string): string => {
    // 1. Check translation loaded from translation files API.
    const fileValue = translationFiles.translations[language]?.[key];
    if (fileValue !== undefined && fileValue !== '') return fileValue;

    // 2. Check built-in static imports (works even before API load).
    const builtIn = builtInTranslations[language];
    if (builtIn) {
      const value = getNestedValue(builtIn, key);
      if (value !== null) return value;
    }

    // 3. Fallback to English.
    return enFlat[key] ?? key;
  }, [language, translationFiles.translations]);

  return (
    <I18nContext.Provider
      value={{
        language,
        setLanguage,
        t,
        languages: translationFiles.languages,
        reloadTranslations,
      }}
    >
      {children}
    </I18nContext.Provider>
  );
}

export function useTranslation() {
  const context = useContext(I18nContext);
  if (context === undefined) {
    throw new Error('useTranslation must be used within an I18nProvider');
  }
  return context;
}

/** Returns all known translation keys (from English as source of truth) */
export function getAllTranslationKeys(): string[] {
  return Object.keys(enFlat);
}

/** Returns the English value for a key (used as reference in admin UI) */
export function getEnglishValue(key: string): string {
  return enFlat[key] ?? key;
}
