import storageAvailable from 'storage-available';
import { v4 as uuidv4 } from 'uuid';

import { isTest } from './environment';
import { loadFromLocalStorage, setInLocalStorage } from './storage';

let currentDeviceId: string;

/**
 * Gets the user agent string with fallbacks
 */
export function getUserAgent() {
  return typeof navigator === 'undefined'
    ? undefined
    : navigator.userAgent || navigator.vendor;
}

/**
 * Gets the user's browser locale
 */
export function getUserLocale(): string | undefined {
  if (typeof navigator === 'undefined') {
    return undefined;
  }

  return (
    navigator.language ||
    (
      navigator as Navigator & {
        userLanguage?: string;
        browserLanguage?: string;
      }
    )?.userLanguage ||
    (
      navigator as Navigator & {
        userLanguage?: string;
        browserLanguage?: string;
      }
    )?.browserLanguage ||
    'en-US'
  );
}

/**
 * Checks if the user agent string against a regex
 */
export function isUserAgent(regex: RegExp, userAgent = getUserAgent()) {
  return regex.test(userAgent || '');
}

/**
 * Checks if the user agent string is a mobile browser
 */
export function isMobileBrowser(userAgent = getUserAgent()) {
  return isUserAgent(
    /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i,
    userAgent
  );
}

/**
 * Checks if the user agent string is an iOS device
 */
export function isIOS(userAgent = getUserAgent()) {
  return isUserAgent(/iphone|ipad|ipod/i, userAgent);
}

/**
 * Checks if the user agent string is an Android device
 */
export function isAndroid(userAgent = getUserAgent()) {
  return isUserAgent(/android/i, userAgent);
}

/**
 * Parses the Safari version from the user agent string
 */
export function parseSafariVersion(userAgent = getUserAgent()) {
  // Disqualify Chrome/Chromium
  if (isUserAgent(/chrome|chromium/i, userAgent) || !userAgent) {
    return null;
  }

  // Safari user agents look roughly like this:
  // - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Safari/605.1.15"
  // - "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Safari/605.1.15"
  const [, semverString] = userAgent.match(/Version\/(\S+)\s+Safari/) || [];

  // Non-Safari or unparseable semver string
  if (!semverString) {
    return null;
  }

  const [major = '0', minor = '0', patch = '0'] = semverString.split('.');
  return {
    major: parseInt(major, 10) || 0,
    minor: parseInt(minor, 10) || 0,
    patch: parseInt(patch, 10) || 0,
  };
}

/**
 * Generates a device ID with the given prefix
 */
export function generateDeviceId(prefix: string = '') {
  return prefix ? `${prefix}${uuidv4()}` : uuidv4();
}

/**
 * Gets the current device ID
 *
 * We persist this device ID in localStorage when possible, but for SSR we
 * prefix it with `default-`.
 *
 * If we don't have a persisted device ID already, we generate a uuid client-side
 */
export function getDeviceId() {
  const canPersistDeviceId =
    typeof window !== 'undefined' && storageAvailable('localStorage');
  // Use the existing device ID or generate a new one if necessary
  let deviceId =
    currentDeviceId ||
    loadFromLocalStorage('ajs_anonymous_id') ||
    generateDeviceId(canPersistDeviceId ? '' : 'default-');
  // Sanitize device ID to letters, numbers, and dashes
  deviceId = deviceId.replace(/[^a-zA-Z0-9-]/g, '');
  // Update current device ID
  currentDeviceId = deviceId;
  if (canPersistDeviceId) {
    setInLocalStorage('ajs_anonymous_id', deviceId);
  }
  return deviceId;
}

/**
 * For use in tests only
 */
export function resetCurrentDeviceId() {
  if (isTest) {
    currentDeviceId = '';
  }
}

/**
 * Gets the current device type based on the user agent string
 */
export function getDeviceType(userAgent = getUserAgent()) {
  if (!userAgent) {
    return 'Unknown';
  } else if (/android/i.test(userAgent)) {
    return 'Android';
  } else if (/iPad|iPhone|iPod/.test(userAgent)) {
    return 'iOS';
  } else if (/Macintosh/i.test(userAgent)) {
    return 'Mac';
  } else if (/Windows/i.test(userAgent)) {
    return 'Windows';
  } else if (/Linux/i.test(userAgent)) {
    return 'Linux';
  }
  return 'Unknown';
}
