import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import type { Member } from "../domain/types";
import type { MemberProfilePatch } from "../data/repos";
import { useRepos } from "../data/DataContext";

type AuthContextValue = {
  member: Member | null;
  loading: boolean;
  /** 最近一次 me() 因暫時性原因失敗（斷網／後端重啟）。登入狀態未知，不是已登出。 */
  unreachable: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  reload: () => Promise<void>;
  updateProfile: (patch: MemberProfilePatch) => Promise<Member>;
};

const AuthContext = createContext<AuthContextValue | null>(null);

export function AuthProvider({ children }: { children: ReactNode }) {
  const repos = useRepos();
  const [member, setMember] = useState<Member | null>(null);
  const [loading, setLoading] = useState(true);
  const [unreachable, setUnreachable] = useState(false);

  const reload = useCallback(async () => {
    // 已進過 app 後不要再把 loading=true：否則 RequireAuth 會卸載整棵 /app，
    // 各頁本地 state（如用量「全體」分頁）會被重掛成預設。
    try {
      const me = await repos.auth.me();
      setMember(me);
      setUnreachable(false);
    } catch {
      // me() 只在 401 回 null，會走到這裡的都是連不上或 5xx。此時 session 很可能還有效，
      // 保留目前的 member，否則使用者會因為一次網路抖動就被踢回登入頁。
      setUnreachable(true);
    } finally {
      setLoading(false);
    }
  }, [repos.auth]);

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

  const login = useCallback(
    async (email: string, password: string) => {
      const { member: m } = await repos.auth.login(email, password);
      setMember(m);
      setUnreachable(false);
    },
    [repos.auth],
  );

  const logout = useCallback(async () => {
    await repos.auth.logout();
    setMember(null);
    setUnreachable(false);
  }, [repos.auth]);

  const updateProfile = useCallback(
    async (patch: MemberProfilePatch) => {
      const next = await repos.auth.updateProfile(patch);
      setMember(next);
      return next;
    },
    [repos.auth],
  );

  const value = useMemo(
    () => ({ member, loading, unreachable, login, logout, reload, updateProfile }),
    [member, loading, unreachable, login, logout, reload, updateProfile],
  );

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

export function useAuth(): AuthContextValue {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used within AuthProvider");
  return ctx;
}
