import { describe, it, expect } from 'vitest';
import { AdminUserViewModel, DashboardStatsViewModel, UserListViewModel } from './AdminUserViewModel';
import type { UserDto, DashboardStats } from '@/lib/api/admin/AdminApiClient';

describe('AdminUserViewModel', () => {
  const createBaseDto = (): UserDto => ({
    id: 'user-123',
    email: 'test@example.com',
    displayName: 'Test User',
    roles: ['user'],
    status: 'active',
    isSystemAdmin: false,
    createdAt: new Date('2024-01-01T00:00:00Z'),
    updatedAt: new Date('2024-01-02T00:00:00Z'),
    lastLoginAt: new Date('2024-01-15T10:30:00Z'),
    primaryDriverId: 'driver-456',
  });

  it('maps core fields from DTO', () => {
    const dto = createBaseDto();
    const vm = new AdminUserViewModel(dto);

    expect(vm.id).toBe('user-123');
    expect(vm.email).toBe('test@example.com');
    expect(vm.displayName).toBe('Test User');
    expect(vm.roles).toEqual(['user']);
    expect(vm.status).toBe('active');
    expect(vm.isSystemAdmin).toBe(false);
    expect(vm.primaryDriverId).toBe('driver-456');
  });

  it('converts dates to Date objects', () => {
    const dto = createBaseDto();
    const vm = new AdminUserViewModel(dto);

    expect(vm.createdAt).toBeInstanceOf(Date);
    expect(vm.updatedAt).toBeInstanceOf(Date);
    expect(vm.lastLoginAt).toBeInstanceOf(Date);
    expect(vm.createdAt.toISOString()).toBe('2024-01-01T00:00:00.000Z');
  });

  it('handles missing lastLoginAt', () => {
    const dto = createBaseDto();
    delete dto.lastLoginAt;
    const vm = new AdminUserViewModel(dto);

    expect(vm.lastLoginAt).toBeUndefined();
    expect(vm.lastLoginFormatted).toBe('Never');
  });

  it('formats role badges correctly', () => {
    const owner = new AdminUserViewModel({ ...createBaseDto(), roles: ['owner'] });
    const admin = new AdminUserViewModel({ ...createBaseDto(), roles: ['admin'] });
    const user = new AdminUserViewModel({ ...createBaseDto(), roles: ['user'] });
    const custom = new AdminUserViewModel({ ...createBaseDto(), roles: ['custom-role'] });

    expect(owner.roleBadges).toEqual(['Owner']);
    expect(admin.roleBadges).toEqual(['Admin']);
    expect(user.roleBadges).toEqual(['User']);
    expect(custom.roleBadges).toEqual(['custom-role']);
  });

  it('derives status badge correctly', () => {
    const active = new AdminUserViewModel({ ...createBaseDto(), status: 'active' });
    const suspended = new AdminUserViewModel({ ...createBaseDto(), status: 'suspended' });
    const deleted = new AdminUserViewModel({ ...createBaseDto(), status: 'deleted' });

    expect(active.statusBadge).toEqual({ label: 'Active', variant: 'performance-green' });
    expect(suspended.statusBadge).toEqual({ label: 'Suspended', variant: 'yellow-500' });
    expect(deleted.statusBadge).toEqual({ label: 'Deleted', variant: 'racing-red' });
  });

  it('formats dates for display', () => {
    const dto = createBaseDto();
    const vm = new AdminUserViewModel(dto);

    expect(vm.lastLoginFormatted).toBe('1/15/2024');
    expect(vm.createdAtFormatted).toBe('1/1/2024');
  });

  it('derives action permissions correctly', () => {
    const active = new AdminUserViewModel({ ...createBaseDto(), status: 'active' });
    const suspended = new AdminUserViewModel({ ...createBaseDto(), status: 'suspended' });
    const deleted = new AdminUserViewModel({ ...createBaseDto(), status: 'deleted' });

    expect(active.canSuspend).toBe(true);
    expect(active.canActivate).toBe(false);
    expect(active.canDelete).toBe(true);

    expect(suspended.canSuspend).toBe(false);
    expect(suspended.canActivate).toBe(true);
    expect(suspended.canDelete).toBe(true);

    expect(deleted.canSuspend).toBe(false);
    expect(deleted.canActivate).toBe(false);
    expect(deleted.canDelete).toBe(false);
  });

  it('handles multiple roles', () => {
    const dto = { ...createBaseDto(), roles: ['owner', 'admin'] };
    const vm = new AdminUserViewModel(dto);

    expect(vm.roleBadges).toEqual(['Owner', 'Admin']);
  });
});

describe('DashboardStatsViewModel', () => {
  const createBaseData = (): DashboardStats => ({
    totalUsers: 100,
    activeUsers: 70,
    suspendedUsers: 10,
    deletedUsers: 20,
    systemAdmins: 5,
    recentLogins: 25,
    newUsersToday: 3,
    userGrowth: [
      { label: 'Mon', value: 5, color: 'text-primary-blue' },
      { label: 'Tue', value: 8, color: 'text-primary-blue' },
    ],
    roleDistribution: [
      { label: 'Owner', value: 2, color: 'text-purple-500' },
      { label: 'Admin', value: 3, color: 'text-blue-500' },
      { label: 'User', value: 95, color: 'text-gray-500' },
    ],
    statusDistribution: {
      active: 70,
      suspended: 10,
      deleted: 20,
    },
    activityTimeline: [
      { date: 'Mon', newUsers: 2, logins: 10 },
      { date: 'Tue', newUsers: 3, logins: 15 },
    ],
  });

  it('maps all core fields from data', () => {
    const data = createBaseData();
    const vm = new DashboardStatsViewModel(data);

    expect(vm.totalUsers).toBe(100);
    expect(vm.activeUsers).toBe(70);
    expect(vm.suspendedUsers).toBe(10);
    expect(vm.deletedUsers).toBe(20);
    expect(vm.systemAdmins).toBe(5);
    expect(vm.recentLogins).toBe(25);
    expect(vm.newUsersToday).toBe(3);
  });

  it('computes active rate correctly', () => {
    const vm = new DashboardStatsViewModel(createBaseData());

    expect(vm.activeRate).toBe(70); // 70%
    expect(vm.activeRateFormatted).toBe('70%');
  });

  it('computes admin ratio correctly', () => {
    const vm = new DashboardStatsViewModel(createBaseData());
    // 5 admins, 95 non-admins => 1:19
    expect(vm.adminRatio).toBe('1:19');
  });

  it('derives activity level correctly', () => {
    const lowEngagement = new DashboardStatsViewModel({
      ...createBaseData(),
      totalUsers: 100,
      recentLogins: 10, // 10% engagement
    });
    expect(lowEngagement.activityLevel).toBe('low');

    const mediumEngagement = new DashboardStatsViewModel({
      ...createBaseData(),
      totalUsers: 100,
      recentLogins: 35, // 35% engagement
    });
    expect(mediumEngagement.activityLevel).toBe('medium');

    const highEngagement = new DashboardStatsViewModel({
      ...createBaseData(),
      totalUsers: 100,
      recentLogins: 60, // 60% engagement
    });
    expect(highEngagement.activityLevel).toBe('high');
  });

  it('handles zero users safely', () => {
    const vm = new DashboardStatsViewModel({
      ...createBaseData(),
      totalUsers: 0,
      activeUsers: 0,
      systemAdmins: 0,
      recentLogins: 0,
    });

    expect(vm.activeRate).toBe(0);
    expect(vm.activeRateFormatted).toBe('0%');
    expect(vm.adminRatio).toBe('1:1');
    expect(vm.activityLevel).toBe('low');
  });

  it('preserves arrays from input', () => {
    const data = createBaseData();
    const vm = new DashboardStatsViewModel(data);

    expect(vm.userGrowth).toEqual(data.userGrowth);
    expect(vm.roleDistribution).toEqual(data.roleDistribution);
    expect(vm.activityTimeline).toEqual(data.activityTimeline);
  });
});

describe('UserListViewModel', () => {
  const createDto = (overrides: Partial<UserDto> = {}): UserDto => ({
    id: 'user-1',
    email: 'test@example.com',
    displayName: 'Test User',
    roles: ['user'],
    status: 'active',
    isSystemAdmin: false,
    createdAt: new Date('2024-01-01'),
    updatedAt: new Date('2024-01-02'),
    ...overrides,
  });

  it('wraps user DTOs in AdminUserViewModel instances', () => {
    const data = {
      users: [createDto({ id: 'user-1' }), createDto({ id: 'user-2' })],
      total: 2,
      page: 1,
      limit: 10,
      totalPages: 1,
    };

    const vm = new UserListViewModel(data);

    expect(vm.users).toHaveLength(2);
    expect(vm.users[0]).toBeInstanceOf(AdminUserViewModel);
    expect(vm.users[0].id).toBe('user-1');
    expect(vm.users[1].id).toBe('user-2');
  });

  it('exposes pagination metadata', () => {
    const data = {
      users: [createDto()],
      total: 50,
      page: 2,
      limit: 10,
      totalPages: 5,
    };

    const vm = new UserListViewModel(data);

    expect(vm.total).toBe(50);
    expect(vm.page).toBe(2);
    expect(vm.limit).toBe(10);
    expect(vm.totalPages).toBe(5);
  });

  it('derives hasUsers correctly', () => {
    const withUsers = new UserListViewModel({
      users: [createDto()],
      total: 1,
      page: 1,
      limit: 10,
      totalPages: 1,
    });

    const withoutUsers = new UserListViewModel({
      users: [],
      total: 0,
      page: 1,
      limit: 10,
      totalPages: 0,
    });

    expect(withUsers.hasUsers).toBe(true);
    expect(withoutUsers.hasUsers).toBe(false);
  });

  it('derives showPagination correctly', () => {
    const withPagination = new UserListViewModel({
      users: [createDto()],
      total: 20,
      page: 1,
      limit: 10,
      totalPages: 2,
    });

    const withoutPagination = new UserListViewModel({
      users: [createDto()],
      total: 5,
      page: 1,
      limit: 10,
      totalPages: 1,
    });

    expect(withPagination.showPagination).toBe(true);
    expect(withoutPagination.showPagination).toBe(false);
  });

  it('calculates start and end indices correctly', () => {
    const vm = new UserListViewModel({
      users: [createDto(), createDto(), createDto()],
      total: 50,
      page: 2,
      limit: 10,
      totalPages: 5,
    });

    expect(vm.startIndex).toBe(11); // (2-1) * 10 + 1
    expect(vm.endIndex).toBe(13); // min(2 * 10, 50)
  });

  it('handles empty list indices', () => {
    const vm = new UserListViewModel({
      users: [],
      total: 0,
      page: 1,
      limit: 10,
      totalPages: 0,
    });

    expect(vm.startIndex).toBe(0);
    expect(vm.endIndex).toBe(0);
  });
});