/* eslint-disable max-len */
import { Helpers } from '../helpers';

// Mock navigator for testing
const mockNavigator = (userAgent: string, maxTouchPoints: number = 0) => {
  Object.defineProperty(window, 'navigator', {
    value: {
      userAgent,
      maxTouchPoints,
    },
    writable: true,
  });
};

const mockScreen = (width: number) => {
  Object.defineProperty(window, 'screen', {
    value: { width },
    writable: true,
  });
};

// Mock touch support
const mockTouchSupport = (hasTouch: boolean) => {
  if (hasTouch) {
    Object.defineProperty(window, 'ontouchstart', {
      value: () => {},
      writable: true,
    });
  } else {
    delete (window as any).ontouchstart;
  }
};

describe('helpers', () => {
  describe('chunkArray', () => {
    it('should split array into chunks', () => {
      const arr = [1, 2, 3, 4, 5, 6, 7, 8];
      const chunks = Helpers.chunkArray(arr, 3);
      expect(chunks).toStrictEqual([
        [1, 2, 3],
        [4, 5, 6],
        [7, 8],
      ]);
    });
    it('should return only one chunk', () => {
      const arr = [1, 2, 3, 4, 5, 6, 7, 8];
      const chunks = Helpers.chunkArray(arr, 10);
      expect(chunks).toStrictEqual([[1, 2, 3, 4, 5, 6, 7, 8]]);
    });
    it('should return an empty array', () => {
      const arr: any[] = [];
      const chunks = Helpers.chunkArray(arr, 10);
      expect(chunks).toStrictEqual([]);
    });
  });

  describe('isMobileDevice', () => {
    afterEach(() => {
      // Reset to default desktop state
      mockNavigator('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
      mockTouchSupport(false);
    });

    it('should return true for iPhone', () => {
      mockNavigator('Mozilla/5.0 (iPhone; CPU iPhone OS 14_0 like Mac OS X) AppleWebKit/605.1.15');
      mockTouchSupport(true);
      expect(Helpers.isMobileDevice()).toBe(true);
    });

    it('should return true for iPad', () => {
      mockNavigator('Mozilla/5.0 (iPad; CPU OS 14_0 like Mac OS X) AppleWebKit/605.1.15');
      mockTouchSupport(true);
      expect(Helpers.isMobileDevice()).toBe(true);
    });

    it('should return true for Android', () => {
      mockNavigator('Mozilla/5.0 (Linux; Android 10; SM-G975F) AppleWebKit/537.36');
      mockTouchSupport(true);
      expect(Helpers.isMobileDevice()).toBe(true);
    });

    it('should return false for desktop without touch', () => {
      mockNavigator('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36');
      mockTouchSupport(false);
      expect(Helpers.isMobileDevice()).toBe(false);
    });

    it('should return false for desktop with touch but no mobile user agent', () => {
      mockNavigator('Mozilla/5.0 (Windows NT 10.0; Touch; Win64; x64) AppleWebKit/537.36');
      mockTouchSupport(true);
      expect(Helpers.isMobileDevice()).toBe(false);
    });

    it('should return false when navigator is undefined', () => {
      Object.defineProperty(window, 'navigator', {
        value: undefined,
        writable: true,
      });
      expect(Helpers.isMobileDevice()).toBe(false);
    });
  });

  describe('getDeviceCategory', () => {
    afterEach(() => {
      mockNavigator('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36', 0);
      mockScreen(1920);
    });

    it('should return "mobile" for iPhone', () => {
      mockNavigator(
        'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15',
        5,
      );
      expect(Helpers.getDeviceCategory()).toBe('mobile');
    });

    it('should return "mobile" for Android phone', () => {
      mockNavigator(
        'Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Mobile Safari/537.36',
        5,
      );
      expect(Helpers.getDeviceCategory()).toBe('mobile');
    });

    it('should return "mobile" for iPad (legacy UA)', () => {
      mockNavigator(
        'Mozilla/5.0 (iPad; CPU OS 12_0 like Mac OS X) AppleWebKit/605.1.15',
        5,
      );
      expect(Helpers.getDeviceCategory()).toBe('mobile');
    });

    it('should return "mobile" for iPad iOS 13+ (Macintosh UA with touch points)', () => {
      mockNavigator(
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15',
        5,
      );
      expect(Helpers.getDeviceCategory()).toBe('mobile');
    });

    it('should return "desktop" for Windows', () => {
      mockNavigator(
        'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        0,
      );
      expect(Helpers.getDeviceCategory()).toBe('desktop');
    });

    it('should return "desktop" for Mac desktop without touch', () => {
      mockNavigator(
        'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36',
        0,
      );
      expect(Helpers.getDeviceCategory()).toBe('desktop');
    });

    it('should return "desktop" for Chrome OS', () => {
      mockNavigator(
        'Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        0,
      );
      expect(Helpers.getDeviceCategory()).toBe('desktop');
    });

    it('should return "desktop" for Linux desktop', () => {
      mockNavigator(
        'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36',
        0,
      );
      expect(Helpers.getDeviceCategory()).toBe('desktop');
    });

    it('should return "other" for PlayStation', () => {
      mockNavigator('Mozilla/5.0 (PlayStation 5) AppleWebKit/605.1.15', 0);
      expect(Helpers.getDeviceCategory()).toBe('other');
    });

    it('should return "other" for Samsung Smart TV (Tizen)', () => {
      mockNavigator('Mozilla/5.0 (SMART-TV; Linux; Tizen 6.0) AppleWebKit/538.1', 0);
      expect(Helpers.getDeviceCategory()).toBe('other');
    });

    it('should return "other" for LG Smart TV (webOS without Mobile)', () => {
      mockNavigator('Mozilla/5.0 (webOS; U; en-US) AppleWebKit/537.36', 0);
      expect(Helpers.getDeviceCategory()).toBe('other');
    });

    it('should return "other" when navigator is undefined', () => {
      Object.defineProperty(window, 'navigator', {
        value: undefined,
        writable: true,
      });
      expect(Helpers.getDeviceCategory()).toBe('other');
    });

    it('should return "other" for completely unknown UA on wide screen without touch', () => {
      mockNavigator('SomeUnknownBrowser/1.0', 0);
      mockScreen(1920);
      expect(Helpers.getDeviceCategory()).toBe('other');
    });

    it('should return "mobile" for unknown UA with touch and small screen', () => {
      mockNavigator('SomeUnknownBrowser/1.0', 1);
      mockScreen(375);
      expect(Helpers.getDeviceCategory()).toBe('mobile');
    });
  });
});
