import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { AuthProviderWithDevBridge } from './AuthProviderWithDevBridge';
import type { DevUserMapper } from './AuthProviderWithDevBridge';
import type { DevUserState } from '@lilith/ui-dev-tools';
import { UserRole } from '@lilith/types';

// Mock @lilith/ui-dev-tools
vi.mock('@lilith/ui-dev-tools', () => ({
  useDevUser: vi.fn(),
}));

// Mock @lilith/sso-client
vi.mock('@lilith/sso-client', () => ({
  SSOClient: vi.fn().mockImplementation(() => ({
    checkSession: vi.fn().mockResolvedValue({ authenticated: false, user: null }),
    startAutoCheck: vi.fn(),
    destroy: vi.fn(),
  })),
}));

// Mock auth-events
vi.mock('./auth-events', () => ({
  authEvents: {
    initialize: vi.fn(),
    subscribe: vi.fn(() => vi.fn()),
    destroy: vi.fn(),
    broadcast: vi.fn(),
  },
}));

import { useDevUser } from '@lilith/ui-dev-tools';

const mockUseDevUser = vi.mocked(useDevUser);

describe('AuthProviderWithDevBridge', () => {
  let queryClient: QueryClient;
  const mockMapDevUser: DevUserMapper = (devUser: DevUserState) => ({
    id: devUser.userId || 'test-id',
    email: `${devUser.primaryType}@test.local`,
    username: devUser.displayName || 'Test User',
    role: UserRole.USER,
    userTypes: [],
    isActive: true,
    emailVerified: true,
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
  });

  beforeEach(() => {
    queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
      },
    });
    vi.clearAllMocks();
  });

  it('should not use dev override when dev mode is disabled', () => {
    mockUseDevUser.mockReturnValue({
      userTypes: ['admin'],
      primaryType: 'admin',
      isAuthenticated: true,
      hasDeclaredIntent: true,
      displayName: 'Admin User',
      userId: 'dev-123',
      isDevMode: false, // Dev mode disabled
      addType: vi.fn(),
      removeType: vi.fn(),
      setPrimaryType: vi.fn(),
      toggleType: vi.fn(),
      hasType: vi.fn(),
      canBePrimary: vi.fn(),
      signOut: vi.fn(),
      signInAsDefault: vi.fn(),
      userTypeConfigs: [],
      getTypeConfig: vi.fn(),
    });

    render(
      <QueryClientProvider client={queryClient}>
        <AuthProviderWithDevBridge
          ssoUrl="https://sso.test.local"
          mapDevUser={mockMapDevUser}
        >
          <div data-testid="child">Child content</div>
        </AuthProviderWithDevBridge>
      </QueryClientProvider>
    );

    expect(screen.getByTestId('child')).toBeInTheDocument();
    // Dev override should not be used when isDevMode is false
  });

  it('should not use dev override when user is not authenticated', () => {
    mockUseDevUser.mockReturnValue({
      userTypes: [],
      primaryType: null,
      isAuthenticated: false, // Not authenticated
      hasDeclaredIntent: false,
      displayName: 'Guest',
      userId: null,
      isDevMode: true,
      addType: vi.fn(),
      removeType: vi.fn(),
      setPrimaryType: vi.fn(),
      toggleType: vi.fn(),
      hasType: vi.fn(),
      canBePrimary: vi.fn(),
      signOut: vi.fn(),
      signInAsDefault: vi.fn(),
      userTypeConfigs: [],
      getTypeConfig: vi.fn(),
    });

    render(
      <QueryClientProvider client={queryClient}>
        <AuthProviderWithDevBridge
          ssoUrl="https://sso.test.local"
          mapDevUser={mockMapDevUser}
        >
          <div data-testid="child">Child content</div>
        </AuthProviderWithDevBridge>
      </QueryClientProvider>
    );

    expect(screen.getByTestId('child')).toBeInTheDocument();
    // Dev override should not be used when not authenticated
  });

  it('should use dev override when dev mode is active and user is authenticated', () => {
    const mockDevUser: DevUserState = {
      userTypes: ['admin'],
      primaryType: 'admin',
      isAuthenticated: true,
      hasDeclaredIntent: true,
      displayName: 'Admin User',
      userId: 'dev-123',
    };

    mockUseDevUser.mockReturnValue({
      ...mockDevUser,
      isDevMode: true,
      addType: vi.fn(),
      removeType: vi.fn(),
      setPrimaryType: vi.fn(),
      toggleType: vi.fn(),
      hasType: vi.fn(),
      canBePrimary: vi.fn(),
      signOut: vi.fn(),
      signInAsDefault: vi.fn(),
      userTypeConfigs: [],
      getTypeConfig: vi.fn(),
    });

    render(
      <QueryClientProvider client={queryClient}>
        <AuthProviderWithDevBridge
          ssoUrl="https://sso.test.local"
          mapDevUser={mockMapDevUser}
        >
          <div data-testid="child">Child content</div>
        </AuthProviderWithDevBridge>
      </QueryClientProvider>
    );

    expect(screen.getByTestId('child')).toBeInTheDocument();
    // mapDevUser should have been called with the dev user state
  });

  it('should call mapDevUser with correct dev user state', () => {
    const mockDevUser: DevUserState = {
      userTypes: ['provider', 'client'],
      primaryType: 'provider',
      isAuthenticated: true,
      hasDeclaredIntent: true,
      displayName: 'Test Provider',
      userId: 'dev-456',
    };

    const spyMapDevUser = vi.fn(mockMapDevUser);

    mockUseDevUser.mockReturnValue({
      ...mockDevUser,
      isDevMode: true,
      addType: vi.fn(),
      removeType: vi.fn(),
      setPrimaryType: vi.fn(),
      toggleType: vi.fn(),
      hasType: vi.fn(),
      canBePrimary: vi.fn(),
      signOut: vi.fn(),
      signInAsDefault: vi.fn(),
      userTypeConfigs: [],
      getTypeConfig: vi.fn(),
    });

    render(
      <QueryClientProvider client={queryClient}>
        <AuthProviderWithDevBridge
          ssoUrl="https://sso.test.local"
          mapDevUser={spyMapDevUser}
        >
          <div data-testid="child">Child content</div>
        </AuthProviderWithDevBridge>
      </QueryClientProvider>
    );

    // mapDevUser should be called
    expect(spyMapDevUser).toHaveBeenCalled();
  });
});
