export interface Detected {
  browser: string;
  version: string;
  opera: boolean;
  ie: boolean;
  support: boolean;
  filedrop: boolean;
  os: 'win' | 'mac' | 'linux';
  platform: 'Windows' | 'Macintosh' | 'Linux' | 'Unknown';
  isMobileWebKit: boolean;
  browserLocales: string[];
  host: string;
}

let _detected: Detected;

export function utilDetect(refresh?: boolean) {
  if (_detected && !refresh) return _detected;
  _detected = <Detected>{};

  const ua = navigator.userAgent;
  let m;

  /* Browser */
  m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);   // Edge
  if (m !== null) {
    _detected.browser = m[1];
    _detected.version = m[2];
  }
  if (!_detected.browser) {
    m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);   // IE11
    if (m !== null) {
      _detected.browser = 'msie';
      _detected.version = m[1];
    }
  }
  if (!_detected.browser) {
    m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);   // Opera 15+
    if (m !== null) {
      _detected.browser = 'Opera';
      _detected.version = m[2];
    }
  }
  if (!_detected.browser) {
    m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
    if (m !== null) {
      _detected.browser = m[1];
      _detected.version = m[2];
      m = ua.match(/version\/([\.\d]+)/i);
      if (m !== null) _detected.version = m[1];
    }
  }
  if (!_detected.browser) {
    _detected.browser = navigator.appName;
    _detected.version = navigator.appVersion;
  }

  // keep major.minor version only..
  _detected.version = _detected.version.split(/\W/).slice(0,2).join('.');

  // detect other browser capabilities
  // Legacy Opera has incomplete svg style support. See #715
  _detected.opera = (_detected.browser.toLowerCase() === 'opera' && Number(_detected.version) < 15 );

  if (_detected.browser.toLowerCase() === 'msie') {
    _detected.ie = true;
    _detected.browser = 'Internet Explorer';
    _detected.support = false;
  } else {
    _detected.ie = false;
    _detected.support = true;
  }

  _detected.filedrop = (window.FileReader && 'ondrop' in window);


  /* Platform */
  if (/Win/.test(ua)) {
    _detected.os = 'win';
    _detected.platform = 'Windows';
  } else if (/Mac/.test(ua)) {
    _detected.os = 'mac';
    _detected.platform = 'Macintosh';
  } else if (/X11/.test(ua) || /Linux/.test(ua)) {
    _detected.os = 'linux';
    _detected.platform = 'Linux';
  } else {
    _detected.os = 'win';
    _detected.platform = 'Unknown';
  }

  _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) ||
    // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
    // so assume any "mac" with multitouch is actually iOS
    (navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1)) &&
    /WebKit/.test(ua) &&
    !/Edge/.test(ua) &&
    // @ts-expect-error -- this attribute is so old that there are no definitions in @types/web
    !window.MSStream;

  /* Locale */
  // An array of locales requested by the browser in priority order.
  _detected.browserLocales = Array.from(new Set( // remove duplicates
      [navigator.language]
        .concat(navigator.languages || [])
        .concat([
            // @ts-expect-error -- this attribute is so old that there are no definitions in @types/web
            // old property for backwards compatibility
            navigator.userLanguage
        ])
        // remove any undefined values
        .filter(Boolean)
    ));


  /* Host */
  let loc;
  try {
    loc = window.top!.location;
  } catch {
    loc = window.location;
  }

  _detected.host = loc.origin + loc.pathname;


  return _detected;
}
