import { Injectable } from '@angular/core';

import { detect, BrowserInfo, BotInfo, NodeInfo } from 'detect-browser';

const deviceTypeList = ['mobile', 'tablet', 'desktop'];

const osTypeList = [
  'ios',
  'iphone',
  'ipad',
  'ipod',
  'android',
  'blackberry',
  'macos',
  'windows',
  'fxos',
  'meego',
  'television'
];

@Injectable({
  providedIn: 'root'
})
export class EnviromentsService {
  private readonly userAgent: string;

  constructor() {
    this.userAgent = window.navigator.userAgent.toLowerCase();
  }

  public macos(): boolean {
    return this.find('mac');
  }

  public ios(): boolean {
    return this.iphone() || this.ipod() || this.ipad();
  }

  public iphone(): boolean {
    return !this.windows() && this.find('iphone');
  }

  public ipod(): boolean {
    return this.find('ipod');
  }

  public ipad(): boolean {
    return this.find('ipad');
  }

  public android(): boolean {
    return !this.windows() && this.find('android');
  }

  public androidPhone(): boolean {
    return this.android() && this.find('mobile');
  }

  public androidTablet(): boolean {
    return this.android() && !this.find('mobile');
  }

  public blackberry(): boolean {
    return this.find('blackberry') || this.find('bb10') || this.find('rim');
  }

  public blackberryPhone(): boolean {
    return this.blackberry() && !this.find('tablet');
  }

  public blackberryTablet(): boolean {
    return this.blackberry() && this.find('tablet');
  }

  public windows(): boolean {
    return this.find('windows');
  }

  public windowsPhone(): boolean {
    return this.windows() && this.find('phone');
  }

  public windowsTablet(): boolean {
    return this.windows() && this.find('touch') && !this.windowsPhone();
  }

  public fxos(): boolean {
    return (this.find('(mobile') || this.find('(tablet')) && this.find(' rv:');
  }

  public fxosPhone(): boolean {
    return this.fxos() && this.find('mobile');
  }

  public fxosTablet(): boolean {
    return this.fxos() && this.find('tablet');
  }

  public meego(): boolean {
    return this.find('meego');
  }

  public cordova(): boolean {
    return (window as any).cordova && location.protocol === 'file:';
  }

  public nodeWebkit(): boolean {
    return typeof (window as any).process === 'object';
  }

  public mobile(): boolean {
    return (
      this.androidPhone() ||
      this.iphone() ||
      this.ipod() ||
      this.windowsPhone() ||
      this.blackberryPhone() ||
      this.fxosPhone() ||
      this.meego()
    );
  }

  public tablet(): boolean {
    return (
      this.ipad() ||
      this.androidTablet() ||
      this.blackberryTablet() ||
      this.windowsTablet() ||
      this.fxosTablet()
    );
  }

  public desktop(): boolean {
    return !this.tablet() && !this.mobile();
  }

  public portrait(): boolean {
    if (
      screen.orientation &&
      Object.prototype.hasOwnProperty.call(window, 'onorientationchange')
    ) {
      return this.includes(screen.orientation.type, 'portrait');
    }
    return window.innerHeight / window.innerWidth > 1;
  }

  public landscape(): boolean {
    if (
      screen.orientation &&
      Object.prototype.hasOwnProperty.call(window, 'onorientationchange')
    ) {
      return this.includes(screen.orientation.type, 'landscape');
    }
    return window.innerHeight / window.innerWidth < 1;
  }

  public type(): string {
    return this.findMatch(deviceTypeList);
  }

  public os(): string {
    return this.findMatch(osTypeList);
  }

  public browser(): BrowserInfo | BotInfo | NodeInfo {
    return detect();
  }

  private includes(haystack: string, needle: string): boolean {
    return haystack.indexOf(needle) !== -1;
  }

  private find(needle: string): boolean {
    return this.includes(this.userAgent, needle);
  }

  private findMatch(arr: string[]): string {
    for (const item of arr) {
      if (this[item]()) {
        return item;
      }
    }
    return 'unknown';
  }
}
