// @vitest-environment jsdom
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { renderHook, waitFor } from '@testing-library/react';
import { resetTabFeatureFlagsCacheForTests, useTabFeatureFlags } from './useTabFeatureFlags';

const { getPlatformAccessTokenMock } = vi.hoisted(() => ({
  getPlatformAccessTokenMock: vi.fn<() => Promise<string>>(),
}));

vi.mock('../lib/authSession', () => ({
  getPlatformAccessToken: getPlatformAccessTokenMock,
}));

vi.mock('../lib/runtime', () => ({
  tradingRuntime: { tradingApiUrl: 'http://localhost:4018' },
}));

describe('useTabFeatureFlags DOM behaviour', () => {
  beforeEach(() => {
    resetTabFeatureFlagsCacheForTests();
    getPlatformAccessTokenMock.mockReset();
    vi.stubGlobal('fetch', vi.fn());
  });

  it('returns defaults while loading when no auth token is available', async () => {
    getPlatformAccessTokenMock.mockRejectedValue(new Error('No session'));

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

    // Initially loading
    expect(result.current.loading).toBe(true);
    expect(result.current.flags).toEqual({ marketplace: true, membership: true });

    await waitFor(() => expect(result.current.loading).toBe(false));

    // Falls back to defaults when unauthenticated
    expect(result.current.flags).toEqual({ marketplace: true, membership: true });
    expect(vi.mocked(fetch)).not.toHaveBeenCalled();
  });

  it('returns flags from the API when authenticated', async () => {
    getPlatformAccessTokenMock.mockResolvedValue('token-xyz');
    vi.mocked(fetch).mockResolvedValue({
      ok: true,
      json: async () => ({
        backtest: { enabled: false, customerEnabled: false },
        tabs: { marketplace: false, membership: true },
      }),
    } as Response);

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

    await waitFor(() => expect(result.current.loading).toBe(false));

    expect(result.current.flags.marketplace).toBe(false);
    expect(result.current.flags.membership).toBe(true);
    expect(vi.mocked(fetch)).toHaveBeenCalledWith(
      'http://localhost:4018/api/feature-flags',
      expect.objectContaining({
        headers: expect.objectContaining({
          Authorization: 'Bearer token-xyz',
        }),
      }),
    );
  });

  it('falls back to defaults when the API returns a non-ok response', async () => {
    getPlatformAccessTokenMock.mockResolvedValue('token-xyz');
    vi.mocked(fetch).mockResolvedValue({
      ok: false,
      status: 503,
    } as Response);

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

    await waitFor(() => expect(result.current.loading).toBe(false));

    expect(result.current.flags).toEqual({ marketplace: true, membership: true });
  });

  it('falls back to defaults when the API returns a malformed body', async () => {
    getPlatformAccessTokenMock.mockResolvedValue('token-xyz');
    vi.mocked(fetch).mockResolvedValue({
      ok: true,
      json: async () => { throw new Error('invalid json'); },
    } as unknown as Response);

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

    await waitFor(() => expect(result.current.loading).toBe(false));

    expect(result.current.flags).toEqual({ marketplace: true, membership: true });
  });

  it('falls back to defaults when fetch itself throws', async () => {
    getPlatformAccessTokenMock.mockResolvedValue('token-xyz');
    vi.mocked(fetch).mockRejectedValue(new Error('network error'));

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

    await waitFor(() => expect(result.current.loading).toBe(false));

    expect(result.current.flags).toEqual({ marketplace: true, membership: true });
  });
});
