# Usage Examples - @dbs-portal/tool-mock

Real-world examples demonstrating common usage patterns and integration scenarios.

## Basic Setup Examples

### Quick Start - Auto Setup

```typescript
// main.tsx
import { autoSetupMocks } from '@dbs-portal/tool-mock'

// Automatically setup MSW based on environment
await autoSetupMocks()

// Start your React app
ReactDOM.createRoot(document.getElementById('root')!).render(<App />)
```

### Manual Setup with Custom Configuration

```typescript
// main.tsx
import { setupMocks, createCrudHandlers } from '@dbs-portal/tool-mock'

await setupMocks({
  config: {
    enabled: process.env.NODE_ENV === 'development',
    mode: 'development',
    logging: true,
    delay: [100, 300],
    errorSimulation: {
      networkErrorRate: 0.01, // 1% network errors
      serverErrorRate: 0.005, // 0.5% server errors
    },
  },
  handlers: [
    ...createCrudHandlers({
      basePath: '/api/users',
      dataFactory: userFactory,
    }),
  ],
})
```

## CRUD Operations

### Complete User Management Example

```typescript
// types/user.ts
export interface User {
  id: string
  email: string
  firstName: string
  lastName: string
  department: string
  role: string
  isActive: boolean
  createdAt: string
  updatedAt: string
}

export interface CreateUserDto {
  email: string
  firstName: string
  lastName: string
  department: string
  role: string
}

export interface UpdateUserDto extends Partial<CreateUserDto> {}
```

```typescript
// mocks/user-factory.ts
import { createDataFactory, generateId } from '@dbs-portal/tool-mock'
import type { User } from '../types/user'

export const userFactory = createDataFactory<User>((overrides = {}) => ({
  id: generateId(),
  email: `user${Math.floor(Math.random() * 1000)}@example.com`,
  firstName: ['John', 'Jane', 'Mike', 'Sarah', 'David'][Math.floor(Math.random() * 5)],
  lastName: ['Doe', 'Smith', 'Johnson', 'Brown', 'Davis'][Math.floor(Math.random() * 5)],
  department: ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance'][Math.floor(Math.random() * 5)],
  role: ['Developer', 'Manager', 'Analyst', 'Coordinator'][Math.floor(Math.random() * 4)],
  isActive: Math.random() > 0.2, // 80% active
  createdAt: new Date(Date.now() - Math.random() * 365 * 24 * 60 * 60 * 1000).toISOString(),
  updatedAt: new Date().toISOString(),
  ...overrides,
}))
```

```typescript
// mocks/user-handlers.ts
import { createCrudHandlers } from '@dbs-portal/tool-mock'
import { userFactory } from './user-factory'

export const userHandlers = createCrudHandlers({
  basePath: '/api/users',
  dataFactory: userFactory,
  initialData: [
    userFactory({ 
      id: '1', 
      email: 'admin@example.com', 
      firstName: 'Admin', 
      lastName: 'User',
      role: 'Admin',
      department: 'IT',
    }),
    userFactory({ 
      id: '2', 
      email: 'manager@example.com', 
      firstName: 'Manager', 
      lastName: 'User',
      role: 'Manager',
      department: 'Engineering',
    }),
    ...Array.from({ length: 48 }, () => userFactory()), // 50 total users
  ],
  pagination: {
    defaultPageSize: 10,
    maxPageSize: 100,
  },
  validate: (data) => {
    const errors: string[] = []
    
    if (!data.email) {
      errors.push('Email is required')
    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
      errors.push('Email format is invalid')
    }
    
    if (!data.firstName) errors.push('First name is required')
    if (!data.lastName) errors.push('Last name is required')
    if (!data.department) errors.push('Department is required')
    if (!data.role) errors.push('Role is required')
    
    return errors.length > 0 ? errors : null
  },
})
```

### Custom Endpoints

```typescript
// mocks/custom-handlers.ts
import { http, HttpResponse } from 'msw'
import { mockResponseBuilder } from '@dbs-portal/tool-mock'
import { userFactory } from './user-factory'

export const customUserHandlers = [
  // Bulk operations
  http.post('/api/users/bulk', async ({ request }) => {
    const { userIds, action } = await request.json()
    
    return mockResponseBuilder()
      .data({
        processedCount: userIds.length,
        action,
        timestamp: new Date().toISOString(),
      })
      .status(200)
      .delay([200, 500])
      .build()
  }),

  // User statistics
  http.get('/api/users/stats', () => {
    return HttpResponse.json({
      success: true,
      data: {
        total: 50,
        active: 40,
        inactive: 10,
        byDepartment: {
          Engineering: 15,
          Marketing: 10,
          Sales: 12,
          HR: 8,
          Finance: 5,
        },
        byRole: {
          Developer: 20,
          Manager: 10,
          Analyst: 12,
          Coordinator: 8,
        },
      },
    })
  }),

  // User search
  http.get('/api/users/search', ({ request }) => {
    const url = new URL(request.url)
    const query = url.searchParams.get('q') || ''
    const department = url.searchParams.get('department')
    
    // Simulate search results
    const results = Array.from({ length: Math.floor(Math.random() * 10) + 1 }, () =>
      userFactory({
        firstName: query ? `${query}Match` : undefined,
        department: department || undefined,
      })
    )
    
    return HttpResponse.json({
      success: true,
      data: results,
      meta: {
        query,
        total: results.length,
      },
    })
  }),

  // User avatar upload
  http.post('/api/users/:id/avatar', ({ params }) => {
    return mockResponseBuilder()
      .data({
        userId: params.id,
        avatarUrl: `https://api.dicebear.com/7.x/avataaars/svg?seed=${params.id}`,
        uploadedAt: new Date().toISOString(),
      })
      .status(201)
      .delay([1000, 2000]) // Simulate file upload time
      .build()
  }),
]
```

## Authentication Examples

### Complete Auth Flow

```typescript
// mocks/auth-handlers.ts
import { createAuthHandlers } from '@dbs-portal/tool-mock'

export const authHandlers = createAuthHandlers('/api/auth', {
  users: [
    {
      id: '1',
      email: 'admin@example.com',
      password: 'admin123',
      firstName: 'Admin',
      lastName: 'User',
      roles: ['admin'],
      permissions: [
        'users:read',
        'users:write',
        'users:delete',
        'roles:read',
        'roles:write',
        'settings:read',
        'settings:write',
      ],
    },
    {
      id: '2',
      email: 'manager@example.com',
      password: 'manager123',
      firstName: 'Manager',
      lastName: 'User',
      roles: ['manager'],
      permissions: [
        'users:read',
        'users:write',
        'roles:read',
      ],
    },
    {
      id: '3',
      email: 'user@example.com',
      password: 'user123',
      firstName: 'Regular',
      lastName: 'User',
      roles: ['user'],
      permissions: [
        'users:read',
      ],
    },
  ],
  tokenExpiry: '1h',
  refreshTokenExpiry: '7d',
  enableRegistration: true,
  enablePasswordReset: true,
})
```

### Protected Routes Example

```typescript
// mocks/protected-handlers.ts
import { withMockAuth, createCrudHandlers } from '@dbs-portal/tool-mock'
import { userFactory } from './user-factory'

// Admin-only user management
const adminUserHandlers = withMockAuth(
  createCrudHandlers({
    basePath: '/api/admin/users',
    dataFactory: userFactory,
  }),
  {
    requireAuth: true,
    requiredRoles: ['admin'],
    requiredPermissions: ['users:write'],
  }
)

// Manager-level user viewing
const managerUserHandlers = withMockAuth(
  [
    http.get('/api/manager/users', () => {
      return HttpResponse.json({
        success: true,
        data: Array.from({ length: 10 }, () => userFactory()),
      })
    }),
  ],
  {
    requireAuth: true,
    requiredRoles: ['manager', 'admin'],
    requiredPermissions: ['users:read'],
  }
)

// User profile (own data only)
const profileHandlers = withMockAuth(
  [
    http.get('/api/profile', ({ request }) => {
      // Extract user from auth token (mocked)
      const authHeader = request.headers.get('Authorization')
      const userId = extractUserIdFromToken(authHeader) // Mock implementation
      
      return HttpResponse.json({
        success: true,
        data: userFactory({ id: userId }),
      })
    }),
  ],
  {
    requireAuth: true,
    // No role/permission requirements - any authenticated user
  }
)
```

## Error Simulation Examples

### Network Conditions

```typescript
// mocks/error-simulation.ts
import { setupMocks, createCrudHandlers } from '@dbs-portal/tool-mock'

await setupMocks({
  config: {
    errorSimulation: {
      networkErrorRate: 0.05, // 5% network errors
      serverErrorRate: 0.02, // 2% server errors
      timeoutErrorRate: 0.01, // 1% timeout errors
      customErrors: [
        {
          pattern: '/api/users',
          method: 'POST',
          error: {
            code: 'RATE_LIMIT_EXCEEDED',
            message: 'Too many requests',
            status: 429,
          },
          probability: 0.1, // 10% chance for user creation
        },
        {
          pattern: /\/api\/users\/\d+/,
          method: 'DELETE',
          error: () => ({
            code: 'CANNOT_DELETE_ADMIN',
            message: 'Cannot delete admin user',
            status: 403,
          }),
          probability: 0.3, // 30% chance for user deletion
        },
      ],
    },
  },
  handlers: [
    ...createCrudHandlers({
      basePath: '/api/users',
      dataFactory: userFactory,
    }),
  ],
})
```

### Specific Error Scenarios

```typescript
// mocks/error-handlers.ts
import { http, HttpResponse } from 'msw'
import { createErrorResponse } from '@dbs-portal/tool-mock'

export const errorHandlers = [
  // Validation errors
  http.post('/api/users', async ({ request }) => {
    const data = await request.json()
    
    // Simulate validation errors
    if (!data.email || !data.firstName) {
      return createErrorResponse({
        code: 'VALIDATION_ERROR',
        message: 'Validation failed',
        details: {
          email: !data.email ? ['Email is required'] : [],
          firstName: !data.firstName ? ['First name is required'] : [],
        },
        status: 400,
      })
    }
    
    // Simulate duplicate email
    if (data.email === 'duplicate@example.com') {
      return createErrorResponse({
        code: 'DUPLICATE_EMAIL',
        message: 'Email already exists',
        status: 409,
      })
    }
    
    // Success case
    return HttpResponse.json({
      success: true,
      data: userFactory(data),
    })
  }),

  // Server errors
  http.get('/api/users/problematic-endpoint', () => {
    return createErrorResponse({
      code: 'INTERNAL_SERVER_ERROR',
      message: 'Something went wrong on our end',
      status: 500,
    })
  }),

  // Timeout simulation
  http.get('/api/users/slow-endpoint', () => {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(HttpResponse.json({
          success: true,
          data: [],
        }))
      }, 10000) // 10 second delay
    })
  }),
]
```

## File Upload Examples

### File Upload Mocking

```typescript
// mocks/file-handlers.ts
import { http, HttpResponse } from 'msw'
import { mockResponseBuilder, generateId } from '@dbs-portal/tool-mock'

export const fileHandlers = [
  // Single file upload
  http.post('/api/files/upload', async ({ request }) => {
    const formData = await request.formData()
    const file = formData.get('file') as File
    
    if (!file) {
      return mockResponseBuilder()
        .error({
          code: 'NO_FILE_PROVIDED',
          message: 'No file provided',
        })
        .status(400)
        .build()
    }
    
    // Simulate file validation
    const maxSize = 10 * 1024 * 1024 // 10MB
    if (file.size > maxSize) {
      return mockResponseBuilder()
        .error({
          code: 'FILE_TOO_LARGE',
          message: 'File size exceeds 10MB limit',
        })
        .status(413)
        .build()
    }
    
    const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf']
    if (!allowedTypes.includes(file.type)) {
      return mockResponseBuilder()
        .error({
          code: 'INVALID_FILE_TYPE',
          message: 'File type not allowed',
        })
        .status(415)
        .build()
    }
    
    // Simulate upload progress (in real app, this would be handled differently)
    return mockResponseBuilder()
      .data({
        id: generateId(),
        filename: file.name,
        originalName: file.name,
        mimeType: file.type,
        size: file.size,
        url: `https://example.com/files/${generateId()}`,
        uploadedAt: new Date().toISOString(),
      })
      .status(201)
      .delay([1000, 3000]) // Simulate upload time
      .build()
  }),

  // Multiple file upload
  http.post('/api/files/upload/multiple', async ({ request }) => {
    const formData = await request.formData()
    const files = formData.getAll('files') as File[]
    
    const uploadedFiles = files.map((file) => ({
      id: generateId(),
      filename: file.name,
      originalName: file.name,
      mimeType: file.type,
      size: file.size,
      url: `https://example.com/files/${generateId()}`,
      uploadedAt: new Date().toISOString(),
    }))
    
    return mockResponseBuilder()
      .data({
        files: uploadedFiles,
        totalCount: uploadedFiles.length,
        totalSize: uploadedFiles.reduce((sum, file) => sum + file.size, 0),
      })
      .status(201)
      .delay([2000, 5000]) // Longer delay for multiple files
      .build()
  }),

  // File download
  http.get('/api/files/:id/download', ({ params }) => {
    // Simulate file content
    const content = new Blob(['Mock file content'], { type: 'text/plain' })
    
    return new HttpResponse(content, {
      status: 200,
      headers: {
        'Content-Type': 'application/octet-stream',
        'Content-Disposition': `attachment; filename="file-${params.id}.txt"`,
      },
    })
  }),
]
```

## Testing Examples

### Component Testing with MSW

```typescript
// __tests__/UserList.test.tsx
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { mockApiCall, userFactory } from '@dbs-portal/tool-mock'
import { UserList } from '../UserList'

const createWrapper = () => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false },
    },
  })
  
  return ({ children }: { children: React.ReactNode }) => (
    <QueryClientProvider client={queryClient}>
      {children}
    </QueryClientProvider>
  )
}

describe('UserList', () => {
  test('should display users', async () => {
    const mockUsers = [
      userFactory({ id: '1', firstName: 'John', lastName: 'Doe' }),
      userFactory({ id: '2', firstName: 'Jane', lastName: 'Smith' }),
    ]
    
    mockApiCall('GET', '/api/users', {
      success: true,
      data: mockUsers,
      meta: { total: 2, page: 1, pageSize: 10 },
    })
    
    render(<UserList />, { wrapper: createWrapper() })
    
    expect(await screen.findByText('John Doe')).toBeInTheDocument()
    expect(await screen.findByText('Jane Smith')).toBeInTheDocument()
  })
  
  test('should handle loading state', async () => {
    mockApiCall('GET', '/api/users', {
      delay: 1000,
      success: true,
      data: [],
    })
    
    render(<UserList />, { wrapper: createWrapper() })
    
    expect(screen.getByText('Loading...')).toBeInTheDocument()
  })
  
  test('should handle error state', async () => {
    mockApiCall('GET', '/api/users', {
      status: 500,
      success: false,
      error: { message: 'Internal server error' },
    })
    
    render(<UserList />, { wrapper: createWrapper() })
    
    expect(await screen.findByText(/error/i)).toBeInTheDocument()
  })
  
  test('should handle user creation', async () => {
    const user = userEvent.setup()
    const newUser = userFactory({ firstName: 'New', lastName: 'User' })
    
    // Mock the create endpoint
    mockApiCall('POST', '/api/users', {
      success: true,
      data: newUser,
    })
    
    // Mock the updated list
    mockApiCall('GET', '/api/users', {
      success: true,
      data: [newUser],
    })
    
    render(<UserList />, { wrapper: createWrapper() })
    
    const createButton = screen.getByRole('button', { name: /create user/i })
    await user.click(createButton)
    
    // Fill form and submit
    await user.type(screen.getByLabelText(/first name/i), 'New')
    await user.type(screen.getByLabelText(/last name/i), 'User')
    await user.click(screen.getByRole('button', { name: /save/i }))
    
    expect(await screen.findByText('New User')).toBeInTheDocument()
  })
})
