"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import type { ReactNode } from "react";
import ar from "@/messages/ar.json";
import en from "@/messages/en.json";

export type Locale = "ar" | "en";
export type Theme = "dark" | "light";
export type Dictionary = typeof ar;

interface AppPreferences {
  locale: Locale;
  theme: Theme;
  dictionary: Dictionary;
  toggleLocale: () => void;
  toggleTheme: () => void;
}

interface ToastMessage {
  id: number;
  message: string;
  tone: "success" | "error" | "info";
}

const PreferencesContext = createContext<AppPreferences | null>(null);
const ToastContext = createContext<((message: string, tone?: ToastMessage["tone"]) => void) | null>(null);

export function AppProviders({ children }: { children: ReactNode }) {
  const [queryClient] = useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: { staleTime: 5_000, retry: 1, refetchOnWindowFocus: false },
          mutations: { retry: 0 },
        },
      }),
  );
  const [locale, setLocale] = useState<Locale>("ar");
  const [theme, setTheme] = useState<Theme>("dark");
  const [toasts, setToasts] = useState<ToastMessage[]>([]);

  useEffect(() => {
    const storedLocale = window.localStorage.getItem("smart-cod-locale");
    const storedTheme = window.localStorage.getItem("smart-cod-theme");
    if (storedLocale === "en") setLocale("en");
    if (storedTheme === "light") setTheme("light");
  }, []);

  useEffect(() => {
    document.documentElement.lang = locale;
    document.documentElement.dir = locale === "ar" ? "rtl" : "ltr";
    window.localStorage.setItem("smart-cod-locale", locale);
  }, [locale]);

  useEffect(() => {
    document.documentElement.dataset.theme = theme;
    window.localStorage.setItem("smart-cod-theme", theme);
  }, [theme]);

  const notify = useCallback((message: string, tone: ToastMessage["tone"] = "info") => {
    const id = Date.now() + Math.random();
    setToasts((current) => [...current, { id, message, tone }]);
    window.setTimeout(() => {
      setToasts((current) => current.filter((toast) => toast.id !== id));
    }, 4_500);
  }, []);

  const preferences = useMemo<AppPreferences>(
    () => ({
      locale,
      theme,
      dictionary: locale === "ar" ? ar : (en as Dictionary),
      toggleLocale: () => setLocale((current) => (current === "ar" ? "en" : "ar")),
      toggleTheme: () => setTheme((current) => (current === "dark" ? "light" : "dark")),
    }),
    [locale, theme],
  );

  return (
    <QueryClientProvider client={queryClient}>
      <PreferencesContext.Provider value={preferences}>
        <ToastContext.Provider value={notify}>
          {children}
          <div className="toast-viewport" aria-live="polite" aria-atomic="true">
            {toasts.map((toast) => (
              <div className={`app-toast app-toast-${toast.tone}`} key={toast.id} role="status">
                <span className="toast-dot" />
                {toast.message}
              </div>
            ))}
          </div>
        </ToastContext.Provider>
      </PreferencesContext.Provider>
    </QueryClientProvider>
  );
}

export function usePreferences() {
  const context = useContext(PreferencesContext);
  if (!context) throw new Error("usePreferences must be used within AppProviders");
  return context;
}

export function useToast() {
  const context = useContext(ToastContext);
  if (!context) throw new Error("useToast must be used within AppProviders");
  return context;
}
