"use client";

import { createContext, useCallback, useContext, useEffect, useMemo } from "react";
import { useRouter, usePathname } from "next/navigation";

import { DEFAULT_LOCALE, isLocale, LOCALE_LABELS, LOCALES, Locale } from "@/app/i18n/locales";
import { getMessages } from "@/app/i18n/getMessages";

interface LanguageContextValue {
  locale: Locale;
  t: (key: string, fallback?: string) => string;
  setLocale: (locale: Locale) => void;
  availableLocales: { code: Locale; label: string }[];
}

const LanguageContext = createContext<LanguageContextValue | null>(null);

function readPath(messages: Record<string, unknown>, key: string): string | undefined {
  const value = key
    .split(".")
    .reduce<unknown>(
      (acc, part) => (acc && typeof acc === "object" ? (acc as Record<string, unknown>)[part] : undefined),
      messages
    );

  return typeof value === "string" ? value : undefined;
}

// Strips a leading /hi or /kn segment (if present) so callers can build
// a fresh locale-prefixed path from whatever page they're currently on.
function stripLocale(pathname: string): string {
  const segments = pathname.split("/");

  if (isLocale(segments[1])) {
    const rest = "/" + segments.slice(2).join("/");
    return rest === "//" ? "/" : rest;
  }

  return pathname;
}

export function LanguageProvider({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const pathname = usePathname();

  // Deriving the active locale from the URL (rather than a value
  // computed once server-side in layout.tsx and passed down as a
  // prop) means it updates on every navigation — including the
  // router.push below — since navigating client-side to another page
  // under the same root layout never re-runs that Server Component,
  // but usePathname() always reflects the current URL.
  const locale = useMemo<Locale>(() => {
    const segments = pathname.split("/");
    return isLocale(segments[1]) ? segments[1] : DEFAULT_LOCALE;
  }, [pathname]);

  // The server sets <html lang> once on the initial request; keep it
  // in sync on client-side navigations too, same reason as `locale`
  // above.
  useEffect(() => {
    document.documentElement.lang = locale;
  }, [locale]);

  const messages = useMemo(() => getMessages(locale), [locale]);

  const t = useCallback(
    (key: string, fallback?: string) => readPath(messages, key) ?? fallback ?? key,
    [messages]
  );

  const setLocale = useCallback(
    (next: Locale) => {
      const unprefixed = stripLocale(pathname);
      const target =
        next === DEFAULT_LOCALE
          ? unprefixed
          : `/${next}${unprefixed === "/" ? "" : unprefixed}`;

      // The proxy re-derives this cookie from the URL on the very next
      // request anyway — setting it here just avoids a flash of the
      // previous language while that navigation is in flight.
      document.cookie = `NEXT_LOCALE=${next}; path=/; max-age=31536000`;
      router.push(target);
    },
    [pathname, router]
  );

  const availableLocales = useMemo(
    () => LOCALES.map((code) => ({ code, label: LOCALE_LABELS[code] })),
    []
  );

  const value = useMemo(
    () => ({ locale, t, setLocale, availableLocales }),
    [locale, t, setLocale, availableLocales]
  );

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

export function useLanguage() {
  const ctx = useContext(LanguageContext);

  if (!ctx) {
    throw new Error("useLanguage must be used within a LanguageProvider");
  }

  return ctx;
}
