import { IMedia, ArrowSize, DeviceCategory } from '../types';
import HistoryService from './history';

export const Helpers = {
  createArray: (length: number): number[] => Array.from({ length }),

  // eslint-disable-next-line max-len
  chunkArray: <T>(array: T[], chunkSize: number): T[][] => Array.from({ length: Math.ceil(array.length / chunkSize) }, (_, i) => array.slice(i * chunkSize, (i + 1) * chunkSize)),

  getAbsoluteBackgroundColor: (element?: Element | null): string => {
    if (!element) {
      return 'white';
    }

    const bg = window.getComputedStyle(element).getPropertyValue('background-color');

    if (bg === 'transparent' || bg === 'rgba(0, 0, 0, 0)') {
      return element.parentElement
        ? Helpers.getAbsoluteBackgroundColor(element.parentElement)
        : 'white';
    }

    return bg;
  },

  isValidJson: (jsonString: string): boolean => {
    try {
      const parsed: unknown = JSON.parse(jsonString);
      return Boolean(parsed) && typeof parsed === 'object';
    } catch {
      return false;
    }
  },

  isMobileDevice: (): boolean => {
    if (typeof navigator === 'undefined') {
      return false;
    }

    const userAgent = navigator.userAgent.toLowerCase();

    // Explicit mobile device patterns - more specific detection
    const mobilePatterns = [
      /android.*mobile/i, // Android phones (not tablets)
      /iphone/i,
      /ipod/i,
      /blackberry/i,
      /windows phone/i,
      /windows ce/i,
      /palm/i,
      /symbian/i,
      /webos/i,
      /mobile/i,
    ];

    // Explicit tablet patterns
    const tabletPatterns = [
      /ipad/i,
      /android(?!.*mobile)/i, // Android tablets
      /tablet/i,
      /kindle/i,
      /playbook/i,
      /nexus.*7/i,
    ];

    // Check for explicit mobile patterns first
    const isMobileUserAgent = mobilePatterns.some((pattern) => pattern.test(userAgent));
    const isTabletUserAgent = tabletPatterns.some((pattern) => pattern.test(userAgent));

    // If it's explicitly a desktop OS, return false regardless of touch
    if (
      /windows nt|mac os x|linux.*x86/i.test(userAgent)
      && !isMobileUserAgent
      && !isTabletUserAgent
    ) {
      return false;
    }

    // Return true only for explicit mobile devices
    return isMobileUserAgent || isTabletUserAgent;
  },

  getDeviceCategory: (): DeviceCategory => {
    if (typeof navigator === 'undefined' || typeof window === 'undefined') {
      return 'other';
    }

    const ua = navigator.userAgent;

    // Gaming consoles and Smart TVs → 'other'
    if (/PlayStation|Xbox|Nintendo|SmartTV|SMART-TV|Tizen|HbbTV|AppleTV|Roku/i.test(ua)) {
      return 'other';
    }

    // webOS Smart TV (LG) without a Mobile token — modern webOS is a TV OS
    if (/webOS/i.test(ua) && !/Mobile/i.test(ua)) {
      return 'other';
    }

    // Chrome OS (Chromebooks) → desktop
    if (/CrOS/i.test(ua)) {
      return 'desktop';
    }

    // iPad iOS 13+ — Safari reports 'Macintosh' but exposes many touch points
    if (/Macintosh/i.test(ua) && navigator.maxTouchPoints > 1) {
      return 'mobile';
    }

    // Explicit mobile phone patterns
    if (/Android.*Mobile|iPhone|iPod|BlackBerry|Windows Phone|IEMobile|Opera Mini/i.test(ua)) {
      return 'mobile';
    }

    // Tablets — touch-first devices, group with mobile
    if (/iPad|Android(?!.*Mobile)|Tablet|Kindle|Silk|PlayBook/i.test(ua)) {
      return 'mobile';
    }

    // Explicit desktop OS patterns
    if (/Windows NT|Macintosh|Mac OS X|Linux/i.test(ua)) {
      return 'desktop';
    }

    // Ambiguous UA: use touch capability and screen width as a final hint
    const hasTouchScreen = navigator.maxTouchPoints > 0;
    const screenWidth = window.screen?.width ?? 1920;
    if (hasTouchScreen && screenWidth <= 768) {
      return 'mobile';
    }

    return 'other';
  },

  pushPostToHistory: (post: IMedia): void => {
    HistoryService.push(post);
  },

  replacePostInHistory: (post: IMedia): void => {
    HistoryService.replace(post);
  },

  uniqId: (): string => `${Date.now()}${Math.floor(Math.random() * 1000)}`,

  randomId: (): string => Math.random().toString(36).slice(2, 10),

  calculateArrowSize: (containerWidth: number): ArrowSize => {
    if (containerWidth < 200) return 'nano';
    if (containerWidth < 300) return 'micro';
    if (containerWidth < 650) return 'small';
    if (containerWidth < 800) return 'compact';
    if (containerWidth < 1000) return 'medium';
    return 'large';
  },
};

export default Helpers;
