import { create } from 'zustand';
import { AuthUser, LoginCredentials, RegisterCredentials } from '../types';
import * as authService from '../services/auth';
import { setAuthToken } from '../services/api';

interface AuthState {
  user: AuthUser | null;
  token: string | null;
  isAuthenticated: boolean;
  isLoading: boolean;

  /** Log in with email/password, store token, load user profile. */
  login: (credentials: LoginCredentials) => Promise<void>;

  /** Register a new account, store token, load user profile. */
  register: (credentials: RegisterCredentials) => Promise<void>;

  /** Log out: clear token and user, notify backend. */
  logout: () => Promise<void>;

  /** Try to load the user from a stored token (called on app start). */
  loadUser: () => Promise<void>;

  /** Set the token manually (e.g., from interceptor storage). */
  setToken: (token: string | null) => void;

  /** Clear auth state without API calls. */
  clearAuth: () => void;
}

export const useAuthStore = create<AuthState>((set, get) => ({
  user: null,
  token: null,
  isAuthenticated: false,
  isLoading: true, // starts true — layout shows spinner on first load

  login: async (credentials: LoginCredentials) => {
    const tokenResponse = await authService.login(credentials);
    const token = tokenResponse.access_token;
    setAuthToken(token);
    set({ token, isAuthenticated: true, isLoading: true });

    try {
      const user = await authService.getCurrentUser();
      set({ user, isAuthenticated: true, isLoading: false });
    } catch {
      // Token obtained but /me failed — still mark as authenticated
      set({ isLoading: false });
    }
  },

  register: async (credentials: RegisterCredentials) => {
    const tokenResponse = await authService.register(credentials);
    const token = tokenResponse.access_token;
    setAuthToken(token);
    set({ token, isAuthenticated: true, isLoading: true });

    try {
      const user = await authService.getCurrentUser();
      set({ user, isAuthenticated: true, isLoading: false });
    } catch {
      set({ isLoading: false });
    }
  },

  logout: async () => {
    setAuthToken(null);
    await authService.logout();
    set({ user: null, token: null, isAuthenticated: false, isLoading: false });
  },

  loadUser: async () => {
    set({ isLoading: true });
    try {
      const storedToken = await authService.getStoredToken();
      if (!storedToken) {
        set({ user: null, token: null, isAuthenticated: false, isLoading: false });
        return;
      }

      // Check token expiry client-side before making API call
      if (authService.isTokenExpired(storedToken)) {
        await authService.clearStoredToken();
        set({ user: null, token: null, isAuthenticated: false, isLoading: false });
        return;
      }

      // Set the token so the axios interceptor can use it
      setAuthToken(storedToken);
      set({ token: storedToken });

      const user = await authService.getCurrentUser();
      set({ user, isAuthenticated: true, isLoading: false });
    } catch {
      // Token invalid or expired — clear it
      await authService.clearStoredToken();
      set({ user: null, token: null, isAuthenticated: false, isLoading: false });
    }
  },

  setToken: (token: string | null) => {
    set({ token, isAuthenticated: !!token });
  },

  clearAuth: () => {
    setAuthToken(null);
    set({ user: null, token: null, isAuthenticated: false, isLoading: false });
  },
}));
