"use client";

import { createContext, useCallback, useContext, useEffect, useMemo, useState, type PropsWithChildren } from "react";

export type Language = "pl" | "en";
type TranslationParams = Record<string, string | number>;

const translations = {
  pl: {
    "nav.weather": "Pogoda",
    "nav.warnings": "Ostrzeżenia",
    "nav.hydro": "Hydro",
    "nav.main": "Główna nawigacja",
    "nav.mobile": "Mobilna nawigacja",
    "language.label": "Wybierz język",
    "language.polish": "Polski",
    "language.english": "English",
    "theme.change": "Zmień motyw",
    "theme.light": "Włącz jasny motyw",
    "theme.dark": "Włącz ciemny motyw",
    "pwa.install": "Zainstaluj",
    "common.noData": "Brak danych",
    "common.loading": "Ładowanie danych",
    "common.retry": "Spróbuj ponownie",
    "error.title": "Nie udało się pobrać danych",
    "error.description": "Sprawdź połączenie i spróbuj ponownie.",
    "dashboard.error": "Nie udało się pobrać listy stacji synoptycznych IMGW.",
    "location.label": "Twoja lokalizacja",
    "location.searchLabel": "Szukaj miejscowości w Polsce",
    "location.placeholder": "Wpisz miejscowość, np. Piaseczno…",
    "location.clear": "Wyczyść wyszukiwanie",
    "location.error": "Nie udało się wyszukać miejscowości. Spróbuj ponownie.",
    "location.preparing": "Przygotowuję listę najbliższych stacji IMGW…",
    "location.empty": "Nie znaleziono pasującej miejscowości w Polsce.",
    "location.nearest": "Najbliższa stacja IMGW",
    "location.currentSource": "{location}: odczyt ze stacji IMGW {station}, około {distance} km.",
    "location.heroSource": "stacja IMGW: {station} · około {distance} km",
    "location.attribution": "Wyszukiwanie miejscowości:",
    "featured.label": "Szybki wybór",
    "featured.title": "Wybrane stacje IMGW",
    "favorites.title": "Ulubione lokalizacje",
    "favorites.empty": "Dodaj stacje do ulubionych, aby mieć ich odczyty pod ręką.",
    "favorites.addStation": "Dodaj {name} do ulubionych",
    "favorites.removeStation": "Usuń {name} z ulubionych",
    "favorites.add": "Dodaj do ulubionych",
    "favorites.remove": "Usuń z ulubionych",
    "weather.humidity": "Wilgotność",
    "weather.wind": "Wiatr",
    "weather.rainfall": "Opad",
    "weather.pressure": "Ciśnienie",
    "weather.feelsLike": "Odczuwalna",
    "weather.measurement": "pomiar",
    "weather.windDirection": "Kierunek wiatru",
    "weather.calm": "Spokojne warunki",
    "weather.humid": "Wilgotno",
    "weather.strongWind": "Silny wiatr",
    "weather.rain": "Opady",
    "weather.heavyRain": "Wyraźne opady",
    "weather.airTemperature": "Temperatura",
    "weather.windSpeed": "Prędkość wiatru",
    "weather.rainfallTotal": "Suma opadu",
    "weather.feelsLikeDetail": "Wartość obliczana, gdy warunki na to pozwalają",
    "weather.humidityDetail": "Wilgotność względna powietrza",
    "weather.pressureDetail": "Ciśnienie atmosferyczne",
    "weather.windSpeedDetail": "Bieżący odczyt IMGW",
    "weather.windDirectionDetail": "Kierunek napływu wiatru",
    "weather.rainfallDetail": "Suma opadu z pomiaru IMGW",
    "weather.temperatureDetail": "Temperatura powietrza",
    "stations.emptyTitle": "Brak pasujących stacji",
    "station.all": "Wszystkie stacje",
    "station.label": "Stacja {name}",
    "station.parameters": "Aktualne parametry",
    "station.parametersDescription": "Najnowszy pomiar udostępniony przez IMGW. Brakujące wartości są oznaczone bez uzupełniania ich danymi szacunkowymi.",
    "station.error": "Nie udało się pobrać danych wybranej stacji IMGW.",
    "station.quality": "Jakość danych",
    "station.lastMeasurementImgw": "Ostatni pomiar IMGW",
    "station.qualityDescription": "Czas poniżej pochodzi bezpośrednio z najnowszego odczytu udostępnionego przez IMGW.",
    "station.lastMeasurement": "Ostatni pomiar",
    "station.source": "Źródło",
    "station.publicApi": "Publiczne API IMGW",
    "snapshot.label": "Snapshot pomiarowy",
    "snapshot.title": "Aktualne proporcje parametrów",
    "snapshot.description": "Wizualizacja bieżącego odczytu. API synoptyczne IMGW nie udostępnia historii ani prognozy godzinowej.",
    "warnings.section": "Komunikaty IMGW",
    "warnings.title": "Ostrzeżenia",
    "warnings.description": "Aktualne ostrzeżenia meteorologiczne i hydrologiczne publikowane przez IMGW. Szczegóły obszaru i czasu obowiązywania pochodzą bezpośrednio z API.",
    "warnings.error": "Nie udało się pobrać ostrzeżeń meteorologicznych ani hydrologicznych.",
    "warnings.emptyTitle": "Brak aktywnych ostrzeżeń",
    "warnings.emptyDescription": "IMGW nie publikuje obecnie ostrzeżeń meteorologicznych ani hydrologicznych.",
    "warnings.drought": "Susza hydrologiczna",
    "warnings.levelUnknown": "Poziom nieokreślony",
    "warnings.level": "Stopień {level}",
    "warnings.hydro": "Hydrologiczne",
    "warnings.meteo": "Meteorologiczne",
    "warnings.untilCancelled": "do odwołania",
    "warnings.areaUnknown": "Obszar nieokreślony",
    "warnings.moreAreas": "i {count} więcej",
    "warnings.probability": "Prawdopodobieństwo: {value}%",
    "warnings.genericHydro": "Ostrzeżenie hydrologiczne",
    "warnings.genericMeteo": "Ostrzeżenie meteorologiczne",
    "hydro.section": "Monitoring wód IMGW",
    "hydro.title": "Hydro",
    "hydro.description": "Najnowsze dostępne pomiary poziomu wody, temperatury i przepływu. Każdy parametr może mieć własny czas aktualizacji.",
    "hydro.error": "Nie udało się pobrać stacji hydrologicznych IMGW.",
    "hydro.searchLabel": "Szukaj stacji hydrologicznej",
    "hydro.searchPlaceholder": "Szukaj stacji, rzeki lub województwa…",
    "hydro.results": "Znaleziono {total} stacji. Wyświetlono {visible}.",
    "hydro.emptyDescription": "Zmień wyszukiwaną nazwę stacji, rzeki lub województwa.",
    "hydro.more": "Pokaż więcej stacji",
    "hydro.riverUnavailable": "Rzeka: brak danych",
    "hydro.level": "Poziom",
    "hydro.water": "Woda",
    "hydro.flow": "Przepływ",
    "hydro.levelMeasurement": "Pomiar poziomu: {date}",
    "offline.title": "Brak połączenia",
    "offline.description": "wtr. nie może teraz pobrać aktualnych danych IMGW. Ostatnio odwiedzone widoki mogą być dostępne z pamięci urządzenia.",
    "offline.back": "Wróć do aplikacji",
  },
  en: {
    "nav.weather": "Weather",
    "nav.warnings": "Warnings",
    "nav.hydro": "Hydro",
    "nav.main": "Main navigation",
    "nav.mobile": "Mobile navigation",
    "language.label": "Select language",
    "language.polish": "Polski",
    "language.english": "English",
    "theme.change": "Change theme",
    "theme.light": "Enable light theme",
    "theme.dark": "Enable dark theme",
    "pwa.install": "Install",
    "common.noData": "No data",
    "common.loading": "Loading data",
    "common.retry": "Try again",
    "error.title": "Unable to load data",
    "error.description": "Check your connection and try again.",
    "dashboard.error": "Unable to load the IMGW synoptic station list.",
    "location.label": "Your location",
    "location.searchLabel": "Search places in Poland",
    "location.placeholder": "Enter a place, e.g. Piaseczno…",
    "location.clear": "Clear search",
    "location.error": "Unable to search for places. Try again.",
    "location.preparing": "Preparing the nearest IMGW stations…",
    "location.empty": "No matching place was found in Poland.",
    "location.nearest": "Nearest IMGW station",
    "location.currentSource": "{location}: reading from IMGW station {station}, approximately {distance} km away.",
    "location.heroSource": "IMGW station: {station} · approximately {distance} km",
    "location.attribution": "Place search:",
    "featured.label": "Quick select",
    "featured.title": "Selected IMGW stations",
    "favorites.title": "Favourite locations",
    "favorites.empty": "Add stations to favourites to keep their readings close at hand.",
    "favorites.addStation": "Add {name} to favourites",
    "favorites.removeStation": "Remove {name} from favourites",
    "favorites.add": "Add to favourites",
    "favorites.remove": "Remove from favourites",
    "weather.humidity": "Humidity",
    "weather.wind": "Wind",
    "weather.rainfall": "Rainfall",
    "weather.pressure": "Pressure",
    "weather.feelsLike": "Feels like",
    "weather.measurement": "measurement",
    "weather.windDirection": "Wind direction",
    "weather.calm": "Calm conditions",
    "weather.humid": "Humid",
    "weather.strongWind": "Strong wind",
    "weather.rain": "Rainfall",
    "weather.heavyRain": "Heavy rainfall",
    "weather.airTemperature": "Temperature",
    "weather.windSpeed": "Wind speed",
    "weather.rainfallTotal": "Rainfall total",
    "weather.feelsLikeDetail": "Calculated when the available conditions allow it",
    "weather.humidityDetail": "Relative air humidity",
    "weather.pressureDetail": "Atmospheric pressure",
    "weather.windSpeedDetail": "Current IMGW reading",
    "weather.windDirectionDetail": "Direction the wind is coming from",
    "weather.rainfallDetail": "Total rainfall from the IMGW reading",
    "weather.temperatureDetail": "Air temperature",
    "stations.emptyTitle": "No matching stations",
    "station.all": "All stations",
    "station.label": "Station {name}",
    "station.parameters": "Current parameters",
    "station.parametersDescription": "The latest measurement published by IMGW. Missing values are clearly marked and never replaced with estimates.",
    "station.error": "Unable to load data for the selected IMGW station.",
    "station.quality": "Data details",
    "station.lastMeasurementImgw": "Latest IMGW measurement",
    "station.qualityDescription": "The time below comes directly from the latest reading published by IMGW.",
    "station.lastMeasurement": "Latest measurement",
    "station.source": "Source",
    "station.publicApi": "Public IMGW API",
    "snapshot.label": "Measurement snapshot",
    "snapshot.title": "Current parameter proportions",
    "snapshot.description": "Visualisation of the current reading. The IMGW synoptic API does not provide historical data or an hourly forecast.",
    "warnings.section": "IMGW notices",
    "warnings.title": "Warnings",
    "warnings.description": "Current meteorological and hydrological warnings published by IMGW. Area and validity details come directly from the API.",
    "warnings.error": "Unable to load meteorological or hydrological warnings.",
    "warnings.emptyTitle": "No active warnings",
    "warnings.emptyDescription": "IMGW is not currently publishing any meteorological or hydrological warnings.",
    "warnings.drought": "Hydrological drought",
    "warnings.levelUnknown": "Level not specified",
    "warnings.level": "Level {level}",
    "warnings.hydro": "Hydrological",
    "warnings.meteo": "Meteorological",
    "warnings.untilCancelled": "until cancelled",
    "warnings.areaUnknown": "Area not specified",
    "warnings.moreAreas": "and {count} more",
    "warnings.probability": "Probability: {value}%",
    "warnings.genericHydro": "Hydrological warning",
    "warnings.genericMeteo": "Meteorological warning",
    "hydro.section": "IMGW water monitoring",
    "hydro.title": "Hydro",
    "hydro.description": "Latest available water level, temperature and flow readings. Each parameter may have a different update time.",
    "hydro.error": "Unable to load IMGW hydrological stations.",
    "hydro.searchLabel": "Search hydrological stations",
    "hydro.searchPlaceholder": "Search by station, river or province…",
    "hydro.results": "Found {total} stations. Showing {visible}.",
    "hydro.emptyDescription": "Adjust the station, river or province name in your search.",
    "hydro.more": "Show more stations",
    "hydro.riverUnavailable": "River: no data",
    "hydro.level": "Level",
    "hydro.water": "Water",
    "hydro.flow": "Flow",
    "hydro.levelMeasurement": "Level measurement: {date}",
    "offline.title": "No connection",
    "offline.description": "wtr. cannot fetch current IMGW data right now. Recently visited views may still be available from your device cache.",
    "offline.back": "Back to the app",
  },
} as const;

export type TranslationKey = keyof typeof translations.pl;

function interpolate(value: string, params?: TranslationParams) {
  if (!params) return value;
  return value.replace(/\{(\w+)\}/g, (_, key: string) => String(params[key] ?? `{${key}}`));
}

export function translate(language: Language, key: TranslationKey, params?: TranslationParams) {
  return interpolate(translations[language][key] ?? translations.en[key], params);
}

interface I18nContextValue {
  language: Language;
  locale: string;
  setLanguage: (language: Language) => void;
  t: (key: TranslationKey, params?: TranslationParams) => string;
}

const I18nContext = createContext<I18nContextValue | null>(null);

export function I18nProvider({ children }: PropsWithChildren) {
  const [language, setLanguageState] = useState<Language>("pl");

  useEffect(() => {
    const stored = window.localStorage.getItem("wtr:language");
    const nextLanguage: Language = stored === "en" ? "en" : "pl";
    const animationFrame = window.requestAnimationFrame(() => setLanguageState(nextLanguage));
    document.documentElement.lang = nextLanguage;
    return () => window.cancelAnimationFrame(animationFrame);
  }, []);

  const setLanguage = useCallback((nextLanguage: Language) => {
    window.localStorage.setItem("wtr:language", nextLanguage);
    document.documentElement.lang = nextLanguage;
    setLanguageState(nextLanguage);
  }, []);

  const value = useMemo<I18nContextValue>(() => ({
    language,
    locale: language === "pl" ? "pl-PL" : "en-GB",
    setLanguage,
    t: (key, params) => translate(language, key, params),
  }), [language, setLanguage]);

  return <I18nContext.Provider value={value}>{children}</I18nContext.Provider>;
}

export function useI18n() {
  const context = useContext(I18nContext);
  if (!context) throw new Error("useI18n must be used within I18nProvider.");
  return context;
}
