import {
  useCallback,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from 'react';
import type { AuthResponse, User } from '../types';
import { api } from '../utils/api';
import { AuthContext } from './AuthContext';

const DEV_MOCK_USER: User = {
  id: 1,
  email: 'htlee@gcsc.co.kr',
  name: '김개발 (DEV)',
  avatarUrl: null,
  status: 'ACTIVE',
  isAdmin: true,
  roles: [{ id: 1, name: 'ADMIN', description: '관리자', urlPatterns: ['/**'], defaultGrant: false }],
  createdAt: new Date().toISOString(),
  lastLoginAt: new Date().toISOString(),
};

function isDevMockSession(): boolean {
  return import.meta.env.DEV && localStorage.getItem('dev-user') === 'true';
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(() =>
    isDevMockSession() ? DEV_MOCK_USER : null,
  );
  const [token, setToken] = useState<string | null>(
    () => localStorage.getItem('token'),
  );
  const [initialized, setInitialized] = useState(
    () => isDevMockSession() || !localStorage.getItem('token'),
  );

  const logout = useCallback(() => {
    const hadToken = !!localStorage.getItem('token') && !isDevMockSession();
    localStorage.removeItem('token');
    localStorage.removeItem('dev-user');
    setToken(null);
    setUser(null);
    if (hadToken) {
      api.post('/auth/logout').catch(() => {});
    }
  }, []);

  const devLogin = useCallback(() => {
    localStorage.setItem('dev-user', 'true');
    localStorage.setItem('token', 'dev-mock-token');
    setToken('dev-mock-token');
    setUser(DEV_MOCK_USER);
    setInitialized(true);
  }, []);

  const login = useCallback(async (googleToken: string) => {
    const res = await api.post<AuthResponse>('/auth/google', {
      idToken: googleToken,
    });
    localStorage.setItem('token', res.token);
    setToken(res.token);
    setUser(res.user);
  }, []);

  useEffect(() => {
    if (!token || isDevMockSession()) return;

    let cancelled = false;
    api
      .get<User>('/auth/me')
      .then((data) => {
        if (!cancelled) setUser(data);
      })
      .catch(() => {
        if (!cancelled) logout();
      })
      .finally(() => {
        if (!cancelled) setInitialized(true);
      });
    return () => {
      cancelled = true;
    };
  }, [token, logout]);

  const loading = !initialized;

  const value = useMemo(
    () => ({ user, token, loading, login, devLogin: import.meta.env.DEV ? devLogin : undefined, logout }),
    [user, token, loading, login, devLogin, logout],
  );

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