import { describe, expect, test, beforeAll, afterAll } from 'bun:test';
import { detectDevice } from './detect-device';

describe('detectDevice', () => {
  const originalNavigator = globalThis.navigator;
  const originalScreen = globalThis.screen;

  const mockEnvironment = (userAgent: string, maxTouchPoints: number, screenWidth: number) => {
    // @ts-expect-error - mocking navigator
    globalThis.navigator = {
      userAgent,
      maxTouchPoints,
    };
    // @ts-expect-error - mocking screen
    globalThis.screen = {
      width: screenWidth,
    };
  };

  afterAll(() => {
    globalThis.navigator = originalNavigator;
    globalThis.screen = originalScreen;
  });

  describe('user agent detection', () => {
    test('detects iPad as Tablet', () => {
      mockEnvironment('Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X)', 0, 1024);
      expect(detectDevice()).toBe('Tablet');
    });

    test('detects tablet keyword as Tablet', () => {
      mockEnvironment('Mozilla/5.0 (Linux; Android 10; SM-T500) Tablet', 0, 800);
      expect(detectDevice()).toBe('Tablet');
    });

    test('detects iPhone as Mobile', () => {
      mockEnvironment('Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X)', 0, 375);
      expect(detectDevice()).toBe('Mobile');
    });

    test('detects iPod as Mobile', () => {
      mockEnvironment('Mozilla/5.0 (iPod touch; CPU iPhone OS 14_0 like Mac OS X)', 0, 320);
      expect(detectDevice()).toBe('Mobile');
    });

    test('detects Android mobile as Mobile', () => {
      mockEnvironment('Mozilla/5.0 (Linux; Android 10; SM-G960F) Mobile', 0, 360);
      expect(detectDevice()).toBe('Mobile');
    });

    test('detects generic mobile keyword as Mobile', () => {
      mockEnvironment('Mozilla/5.0 Mobile Safari', 0, 400);
      expect(detectDevice()).toBe('Mobile');
    });
  });

  describe('touch and screen size detection', () => {
    test('touch device with small screen is Mobile', () => {
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 5, 600);
      expect(detectDevice()).toBe('Mobile');
    });

    test('touch device with medium screen is Tablet', () => {
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 5, 800);
      expect(detectDevice()).toBe('Tablet');
    });

    test('touch device at 768px boundary is Tablet', () => {
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 5, 768);
      expect(detectDevice()).toBe('Tablet');
    });

    test('touch device at 1280px boundary is Tablet', () => {
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 5, 1280);
      expect(detectDevice()).toBe('Tablet');
    });

    test('touch device above 1280px is Desktop', () => {
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 5, 1400);
      expect(detectDevice()).toBe('Desktop');
    });
  });

  describe('desktop detection', () => {
    test('non-touch device with large screen is Desktop', () => {
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0; Win64; x64)', 0, 1920);
      expect(detectDevice()).toBe('Desktop');
    });

    test('non-touch device with small screen is still Desktop', () => {
      // No touch and no mobile UA means desktop regardless of screen size
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 0, 600);
      expect(detectDevice()).toBe('Desktop');
    });

    test('single touch point (mouse) is not considered touch', () => {
      // maxTouchPoints = 1 means mouse, not touch screen
      mockEnvironment('Mozilla/5.0 (Windows NT 10.0)', 1, 800);
      expect(detectDevice()).toBe('Desktop');
    });
  });

  describe('case insensitivity', () => {
    test('detects IPAD in uppercase', () => {
      mockEnvironment('Mozilla/5.0 IPAD something', 0, 1024);
      // UA is lowercased in the function
      expect(detectDevice()).toBe('Tablet');
    });

    test('detects Mobile in mixed case', () => {
      mockEnvironment('Mozilla/5.0 MoBiLe Safari', 0, 375);
      expect(detectDevice()).toBe('Mobile');
    });
  });

  describe('priority of detection', () => {
    test('tablet UA takes priority over mobile-sized touch screen', () => {
      // iPad UA should return Tablet even with small screen
      mockEnvironment('Mozilla/5.0 (iPad)', 5, 500);
      expect(detectDevice()).toBe('Tablet');
    });

    test('mobile UA takes priority over tablet-sized touch screen', () => {
      // iPhone UA should return Mobile even with tablet-sized screen
      mockEnvironment('Mozilla/5.0 (iPhone)', 5, 1000);
      expect(detectDevice()).toBe('Mobile');
    });
  });
});
