"use client";

import {
  createContext,
  useCallback,
  useContext,
  useLayoutEffect,
  useMemo,
  useState,
} from "react";
import { translate, type Lang } from "@/lib/i18n";
import type { ThemeName } from "@/lib/theme";
import {
  LANG_STORAGE_KEY,
  THEME_STORAGE_KEY,
  parseSavedLang,
  parseSavedTheme,
} from "@/lib/ui-prefs";

interface ThemeContextValue {
  theme: ThemeName;
  lang: Lang;
  toggleTheme: () => void;
  toggleLang: () => void;
  t: (text: string) => string;
}

const ThemeContext = createContext<ThemeContextValue | null>(null);

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  // ★既定（dark / ja）で始める★ — サーバーも既定で描くので、最初の描画を一致させる（ハイドレーションの不一致を避ける）。
  // ★保存値は下の useLayoutEffect で読む（描く前）★。`useState(() => localStorage…)` にしないこと（指示書BC 3-0・D-183）
  const [theme, setTheme] = useState<ThemeName>("dark");
  const [lang, setLang] = useState<Lang>("ja");
  /** 保存値を読み終えたか。★読み終える前は <html> にも localStorage にも書かない★（既定値で上書きしない） */
  const [prefsLoaded, setPrefsLoaded] = useState(false);

  // ★保存した表示設定を、ハイドレーションの直後・描く前に読む★（ユーザー決定 2026-10-19 U1）。
  //   <html> の data-theme / lang は <head> のスクリプト（app/layout.tsx の PREFS_INLINE_SCRIPT）が先に入れている。
  //   ここでは JS で色・文字を決めている部品（THEME_TOKENS[theme]・t()）のために state を合わせる。
  //   開発時の Strict Mode の再マウントで React が <html> の属性を消すので、下の effect が入れ直す（ガイドの「Re-applying attributes」）
  useLayoutEffect(() => {
    let savedTheme: ThemeName | null = null;
    let savedLang: Lang | null = null;
    try {
      savedTheme = parseSavedTheme(window.localStorage.getItem(THEME_STORAGE_KEY));
      savedLang = parseSavedLang(window.localStorage.getItem(LANG_STORAGE_KEY));
    } catch {
      // ★使えない環境（プライベートウィンドウ等）は既定のまま★
    }
    // eslint-disable-next-line react-hooks/set-state-in-effect -- 保存した表示設定を描く前に反映する（D-183）
    if (savedTheme) setTheme(savedTheme);
    if (savedLang) setLang(savedLang);
    setPrefsLoaded(true);
  }, []);

  useLayoutEffect(() => {
    if (!prefsLoaded) return;
    document.documentElement.dataset.theme = theme;
    document.documentElement.lang = lang === "ja" ? "ja" : "en";
    try {
      window.localStorage.setItem(THEME_STORAGE_KEY, theme);
      window.localStorage.setItem(LANG_STORAGE_KEY, lang);
    } catch {
      // ★保存できなくても画面は切り替わる★（その閲覧中だけ有効）
    }
  }, [theme, lang, prefsLoaded]);

  const toggleTheme = useCallback(() => {
    setTheme((prev) => (prev === "dark" ? "light" : "dark"));
  }, []);

  const toggleLang = useCallback(() => {
    setLang((prev) => (prev === "ja" ? "en" : "ja"));
  }, []);

  const t = useCallback((text: string) => translate(lang, text), [lang]);

  const value = useMemo(
    () => ({ theme, lang, toggleTheme, toggleLang, t }),
    [theme, lang, toggleTheme, toggleLang, t]
  );

  return (
    <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>
  );
}

export function useTheme(): ThemeContextValue {
  const ctx = useContext(ThemeContext);
  if (!ctx) {
    throw new Error("useTheme must be used within ThemeProvider");
  }
  return ctx;
}
