import { describe, it, expect, vi, beforeEach } from 'vitest';
import { renderHook } from '@testing-library/react';

const { mockUseSession, mockUseSWR, mockApiClient } = vi.hoisted(() => ({
  mockUseSession: vi.fn(),
  mockUseSWR: vi.fn(),
  mockApiClient: {
    _accessToken: null as string | null,
    set accessToken(token: string) {
      this._accessToken = token;
    },
    get hasToken() {
      return this._accessToken !== null;
    },
  },
}));

vi.mock('next-auth/react', () => ({
  useSession: mockUseSession,
}));

vi.mock('swr', () => ({
  default: mockUseSWR,
}));

vi.mock('@/services/api-client', () => ({
  apiClient: mockApiClient,
}));

import { useApi } from '../../src/lib/useApi';

beforeEach(() => {
  vi.clearAllMocks();
  mockApiClient._accessToken = null;
});

describe('useApi', () => {
  it('returns loading state when session is loading', () => {
    mockUseSession.mockReturnValue({ data: null, status: 'loading' });
    mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: false });

    const { result } = renderHook(() => useApi());

    expect(result.current.isLoading).toBe(true);
    expect(result.current.isAuthenticated).toBe(false);
    expect(result.current.householdId).toBeNull();
  });

  it('returns unauthenticated state', () => {
    mockUseSession.mockReturnValue({ data: null, status: 'unauthenticated' });
    mockUseSWR.mockReturnValue({ data: undefined, mutate: vi.fn(), isLoading: false });

    const { result } = renderHook(() => useApi());

    expect(result.current.isAuthenticated).toBe(false);
    expect(result.current.isLoading).toBe(false);
  });

  it('sets token on apiClient when session has accessToken', () => {
    mockUseSession.mockReturnValue({
      data: { accessToken: 'test-jwt' },
      status: 'authenticated',
    });
    mockUseSWR.mockReturnValue({
      data: { householdIds: ['hh1'], displayName: 'Test' },
      mutate: vi.fn(),
      isLoading: false,
    });

    renderHook(() => useApi());

    expect(mockApiClient._accessToken).toBe('test-jwt');
  });

  it('returns householdId from profile', () => {
    mockUseSession.mockReturnValue({
      data: { accessToken: 'test-jwt' },
      status: 'authenticated',
    });
    mockUseSWR.mockReturnValue({
      data: { householdIds: ['hh1', 'hh2'], displayName: 'Test' },
      mutate: vi.fn(),
      isLoading: false,
    });

    const { result } = renderHook(() => useApi());

    expect(result.current.householdId).toBe('hh1');
    expect(result.current.householdIds).toEqual(['hh1', 'hh2']);
    expect(result.current.isAuthenticated).toBe(true);
  });

  it('returns null householdId when profile has no households', () => {
    mockUseSession.mockReturnValue({
      data: { accessToken: 'test-jwt' },
      status: 'authenticated',
    });
    mockUseSWR.mockReturnValue({
      data: { householdIds: [] },
      mutate: vi.fn(),
      isLoading: false,
    });

    const { result } = renderHook(() => useApi());

    expect(result.current.householdId).toBeNull();
  });

  it('returns loading when authenticated but profile is still loading', () => {
    mockUseSession.mockReturnValue({
      data: { accessToken: 'test-jwt' },
      status: 'authenticated',
    });
    mockUseSWR.mockReturnValue({
      data: undefined,
      mutate: vi.fn(),
      isLoading: true,
    });

    const { result } = renderHook(() => useApi());

    expect(result.current.isLoading).toBe(true);
  });

  it('provides refreshProfile function from SWR mutate', () => {
    const mutateFn = vi.fn();
    mockUseSession.mockReturnValue({
      data: { accessToken: 'test-jwt' },
      status: 'authenticated',
    });
    mockUseSWR.mockReturnValue({
      data: { householdIds: ['hh1'] },
      mutate: mutateFn,
      isLoading: false,
    });

    const { result } = renderHook(() => useApi());

    expect(result.current.refreshProfile).toBe(mutateFn);
  });
});
