import { DevicesService } from './devices.service';

describe('DevicesService Device Locking & Anti-Proxy', () => {
  let service: DevicesService;
  let mockDb: any;

  beforeEach(() => {
    mockDb = {
      teacher_devices: {
        findFirst: jest.fn(),
        create: jest.fn(),
        update: jest.fn(),
        delete: jest.fn(),
      },
      device_change_requests: {
        findFirst: jest.fn(),
        create: jest.fn(),
        update: jest.fn(),
        findMany: jest.fn(),
      },
    };
    service = new DevicesService(mockDb);
  });

  it('should automatically bind device on first login/attendance', async () => {
    mockDb.teacher_devices.findFirst
      .mockResolvedValueOnce(null) // No other teacher bound to this device
      .mockResolvedValueOnce(null); // This teacher not yet bound

    const result = await service.validateOrBindDevice(
      'teacher-1',
      'owner-1',
      'device-uuid-123',
      'Galaxy S22',
      '192.168.1.5',
    );

    expect(result.valid).toBe(true);
    expect(mockDb.teacher_devices.create).toHaveBeenCalledWith(
      expect.objectContaining({
        data: expect.objectContaining({
          member_id: 'teacher-1',
          device_id: 'device-uuid-123',
        }),
      }),
    );
  });

  it('should allow access when matching bound device', async () => {
    mockDb.teacher_devices.findFirst
      .mockResolvedValueOnce({ member_id: 'teacher-1', device_id: 'device-uuid-123' }) // Not other teacher
      .mockResolvedValueOnce({ id: 'binding-1', member_id: 'teacher-1', device_id: 'device-uuid-123' }); // Bound device

    const result = await service.validateOrBindDevice(
      'teacher-1',
      'owner-1',
      'device-uuid-123',
      'Galaxy S22',
      '192.168.1.5',
    );

    expect(result.valid).toBe(true);
    expect(mockDb.teacher_devices.update).toHaveBeenCalled();
  });

  it('should block access when teacher tries from a different device', async () => {
    mockDb.teacher_devices.findFirst
      .mockResolvedValueOnce(null) // Not another teacher
      .mockResolvedValueOnce({ id: 'binding-1', member_id: 'teacher-1', device_id: 'original-device-uuid' }); // Bound to original

    const result = await service.validateOrBindDevice(
      'teacher-1',
      'owner-1',
      'new-unregistered-device-uuid',
      'iPhone 15',
      '192.168.1.5',
    );

    expect(result.valid).toBe(false);
    expect(result.message).toContain('Device mismatch');
  });

  it('should detect proxy attendance when device is already bound to another teacher', async () => {
    mockDb.teacher_devices.findFirst.mockResolvedValueOnce({
      member_id: 'teacher-2',
      device_id: 'shared-device-uuid',
      member: { first_name: 'John', last_name: 'Doe' },
    });

    const result = await service.validateOrBindDevice(
      'teacher-1',
      'owner-1',
      'shared-device-uuid',
      'Shared Phone',
      '192.168.1.5',
    );

    expect(result.valid).toBe(false);
    expect(result.message).toContain('Proxy attendance detected');
  });
});
