// 이 파일이 하는 일: "지금 누가 로그인해 있는가"를 앱 전체에서 공유하는 Context.
// 앱이 처음 뜰 때 GET /api/auth/me로 세션을 확인하고,
// login()/logout() 함수를 하위 컴포넌트에 내려준다.
import { createContext, useContext, useEffect, useState } from 'react';
import client from './api/client';

// 학습 포인트: Context는 "props를 여러 단계 내려보내는 번거로움"을 해결한다.
// 사용자 정보처럼 앱 전역에서 필요한 값에 딱 맞는 도구다.
// Context가 없다면? App → Layout → 각 페이지 → 버튼까지 user를 props로
// 일일이 전달해야 하고, 중간 컴포넌트들은 쓰지도 않는 값을 나르기만 하게 된다.
// (이걸 "prop drilling"이라고 부른다.)
const AuthContext = createContext(null);

export function AuthProvider({ children }) {
  // user: 로그인한 사용자 객체 {id, username, name, role, track} 또는 null
  const [user, setUser] = useState(null);
  // loading: 새로고침 직후 /auth/me 확인이 끝나기 전인지 여부.
  // 학습 포인트: 이 플래그가 없으면 새로고침할 때마다
  // "아직 확인 중인데 user가 null이니까" 로그인 페이지로 튕겨버린다.
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // 앱 최초 로딩 시 세션 쿠키가 살아 있는지 서버에 물어본다.
    //
    // 학습 포인트 — 비동기 경쟁(race condition) 방어.
    // 이 요청이 끝나기 전에 사용자가 로그인을 마칠 수 있다(자동완성 + 빠른 제출).
    // 그때 뒤늦게 도착한 /auth/me의 401이 setUser(null)로 로그인 결과를 덮으면,
    // 로그인은 성공했는데 화면은 로그인 페이지로 튕기는 황당한 버그가 된다.
    // 그래서 함수형 업데이트로 "이미 로그인돼 있으면 건드리지 않는다":
    //   prev가 있으면(=login()이 먼저 끝남) 그대로 두고, 없을 때만 결과를 적용한다.
    client
      .get('/auth/me')
      .then((res) => setUser((prev) => prev ?? res.data))
      .catch(() => setUser((prev) => prev)) // 401 = 비로그인. 단, 먼저 끝난 로그인은 보존
      .finally(() => setLoading(false));
  }, []);

  async function login(username, password) {
    // 실패하면 axios가 예외를 던지므로 호출한 쪽(LoginPage)에서 try/catch로 잡는다.
    const res = await client.post('/auth/login', { username, password });
    setUser(res.data);
    return res.data;
  }

  async function logout() {
    await client.post('/auth/logout');
    setUser(null);
  }

  return (
    <AuthContext.Provider value={{ user, loading, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

// 학습 포인트: useContext를 감싼 커스텀 훅.
// 각 페이지는 `const { user } = useAuth()` 한 줄이면 된다.
export function useAuth() {
  return useContext(AuthContext);
}
