import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useAuthStore } from './auth';

// Mock the lib/db + lib/offlineAuth + ./api modules that auth.ts imports —
// these are pulled in transitively and would otherwise try to talk to a
// real server / open IndexedDB during unit tests.
vi.mock('../lib/db', () => ({
  initDB: vi.fn().mockResolvedValue(undefined),
  verifyPassword: vi.fn().mockResolvedValue({ ok: false, reason: 'not found' }),
  cacheHash: vi.fn().mockResolvedValue(undefined),
}));
vi.mock('../lib/offlineAuth', () => ({
  mintOfflineToken: vi.fn().mockResolvedValue('offline.jwt.token'),
  cacheOfflineJwtSecret: vi.fn(),
}));
vi.mock('./api', () => {
  const mockPost = vi.fn();
  const mockGet = vi.fn();
  return {
    default: {
      post: mockPost,
      get: mockGet,
    },
  };
});

const reset = () => {
  useAuthStore.setState({ token: null, user: null, offline: false });
  localStorage.clear();
};

describe('useAuthStore', () => {
  beforeEach(() => {
    reset();
    vi.clearAllMocks();
  });

  it('starts in a logged-out state', () => {
    const s = useAuthStore.getState();
    expect(s.token).toBeNull();
    expect(s.user).toBeNull();
    expect(s.offline).toBe(false);
    expect(s.isAuthenticated()).toBe(false);
  });

  it('logout() clears token, user, and offline flag', () => {
    useAuthStore.setState({ token: 'abc', user: { id: 1, email: 'x', role: 'student' } as any, offline: true });
    expect(useAuthStore.getState().isAuthenticated()).toBe(true);
    useAuthStore.getState().logout();
    const s = useAuthStore.getState();
    expect(s.token).toBeNull();
    expect(s.user).toBeNull();
    expect(s.offline).toBe(false);
    expect(s.isAuthenticated()).toBe(false);
  });

  it('updateUser() merges into the existing user object', () => {
    useAuthStore.setState({ user: { id: 1, email: 'a@b.com', role: 'student', first_name: 'A', last_name: 'B' } as any });
    useAuthStore.getState().updateUser({ first_name: 'Alpha' });
    const u = useAuthStore.getState().user!;
    expect(u.first_name).toBe('Alpha');
    expect(u.last_name).toBe('B'); // preserved
    expect(u.id).toBe(1);
  });

  it('updateUser() is a no-op when there is no user', () => {
    useAuthStore.getState().updateUser({ first_name: 'X' });
    expect(useAuthStore.getState().user).toBeNull();
  });
});
