import { Observable, Subject } from 'rxjs';

import {
  NativeService,
  WindowState,
  NotificationRequest,
  WindowIdle,
  UpdateInfo,
  UpdateCheckConfig,
  NotificationType,
  NativePathName,
  NativeType
} from '@ucap-webmessenger/native';
import { HttpClient } from '@angular/common/http';
import { map, share, take } from 'rxjs/operators';
import { TranslateLoader } from '@ngx-translate/core';
import { TranslateLoaderService } from '../translate/browser-loader';
import { NotificationService } from '../notification/notification.service';
import { Injectable } from '@angular/core';
import { FileUtil, StatusCode } from '@ucap-webmessenger/core';

@Injectable({
  providedIn: 'root'
})
export class BrowserNativeService extends NativeService {
  private notificationService: NotificationService;

  private chatOpenRoomSubject: Subject<string> | null = null;
  private chatOpenRoom$: Observable<string> | null = null;

  private msgOpenMessageSubject: Subject<string> | null = null;
  private msgOpenMessage$: Observable<string> | null = null;

  type(): NativeType {
    return NativeType.Browser;
  }

  postAppInit(): void {
    this.notificationService.requestPermission();
  }

  logout(): Observable<void> {
    return new Observable<void>(subscriber => {
      try {
      } catch (error) {
        subscriber.error(error);
      } finally {
        subscriber.complete();
      }
    });
  }

  changeStatus(): Observable<StatusCode> {
    return new Observable<StatusCode>(subscriber => {
      try {
      } catch (error) {
        subscriber.error(error);
      } finally {
        subscriber.complete();
      }
    });
  }

  showSetting(): Observable<void> {
    return new Observable<void>(subscriber => {
      try {
      } catch (error) {
        subscriber.error(error);
      } finally {
        subscriber.complete();
      }
    });
  }

  getNetworkInfo(): Promise<any> {
    return new Promise<any>((resolve, reject) => {
      resolve([{ ip: 'Browser', mac: 'browser' }]);
    });
  }

  getVersionInfo(): Promise<string> {
    return new Promise<any>((resolve, reject) => {
      resolve('');
    });
  }

  changeAutoLaunch(autoLaunch: boolean): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
      resolve(true);
    });
  }

  changeStartupHideWindow(startupHideWindow: boolean): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
      resolve(true);
    });
  }

  changeDownloadPath(downloadPath: string): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      resolve(downloadPath);
    });
  }

  notify(noti: NotificationRequest): void {
    this.notificationService.notify(noti, () => {
      window.focus();
      if (noti.type === NotificationType.Event) {
        this.chatOpenRoomSubject.next(noti.seq);
      } else if (noti.type === NotificationType.Message) {
        this.msgOpenMessageSubject.next(noti.seq);
      }
    });
  }
  closeAllNotify(): void {}

  checkForUpdates(currentVersion: string): void {}

  checkForInstantUpdates(config: UpdateCheckConfig): Observable<UpdateInfo> {
    return new Observable<UpdateInfo>(subscriber => {
      try {
      } catch (error) {
        subscriber.error(error);
      } finally {
        subscriber.complete();
      }
    });
  }

  applyInstantUpdates(): void {}

  showImageViewer(): void {}

  readFile(path: string): Promise<Buffer> {
    return new Promise<Buffer>((resolve, reject) => {
      this.httpClient
        .get(path, { responseType: 'arraybuffer' })
        .pipe(take(1))
        .subscribe(arraybuffer => {
          resolve(Buffer.from(arraybuffer));
        });
    });
  }

  saveFile(
    buffer: Buffer,
    fileName: string,
    mimeType: string,
    path?: string
  ): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      try {
        FileUtil.save(buffer, fileName, mimeType).then(fn => {
          resolve(fn);
        });
      } catch (error) {
        reject(error);
      }
    });
  }

  openDefaultDownloadFolder(): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
      resolve(true);
    });
  }
  openTargetFolder(folderPath?: string, make?: boolean): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
      resolve(true);
    });
  }
  openTargetItem(filePath?: string): Promise<boolean> {
    return new Promise<boolean>((resolve, reject) => {
      resolve(true);
    });
  }

  getPath(name: NativePathName): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      resolve('');
    });
  }

  selectDirectory(): Promise<string> {
    return new Promise<string>((resolve, reject) => {
      resolve('');
    });
  }

  selectSaveFilePath(
    defaultPath?: string
  ): Promise<{
    canceled: boolean;
    filePath: string;
  }> {
    return new Promise<{
      canceled: boolean;
      filePath: string;
    }>((resolve, reject) => {
      resolve({
        canceled: false,
        filePath: ''
      });
    });
  }

  executeProcess(executableName: string): Promise<number> {
    return new Promise<number>((resolve, reject) => {
      resolve(-1);
    });
  }

  windowStateChanged(): Observable<WindowState> {
    return new Observable<WindowState>(subscriber => {
      try {
        subscriber.next(WindowState.Normal);
      } catch (error) {
        subscriber.error(error);
      } finally {
        subscriber.complete();
      }
    });
  }

  windowClose(): void {}

  windowMinimize(): void {}

  windowMaximize(): void {}

  appExit(): void {}

  zoomTo(factor: number): Promise<number> {
    return new Promise<number>((resolve, reject) => {
      resolve(-1);
    });
  }

  idleStateChanged(): Observable<WindowIdle> {
    return new Observable<WindowIdle>(subscriber => {
      try {
      } catch (error) {
        subscriber.error(error);
      } finally {
        subscriber.complete();
      }
    });
  }

  idleStateStop(): void {}

  changeLimitOfIdleState(limitTime: number): void {}

  chatOpenRoom(): Observable<string> {
    if (!this.chatOpenRoomSubject) {
      this.chatOpenRoomSubject = new Subject<WindowIdle>();
      this.chatOpenRoom$ = this.chatOpenRoomSubject
        .asObservable()
        .pipe(share());
    }

    return this.chatOpenRoom$;
  }

  msgOpenMessage(): Observable<string> {
    if (!this.msgOpenMessageSubject) {
      this.msgOpenMessageSubject = new Subject<WindowIdle>();
      this.msgOpenMessage$ = this.msgOpenMessageSubject
        .asObservable()
        .pipe(share());
    }

    return this.msgOpenMessage$;
  }

  getTranslateLoader(prefix?: string, suffix?: string): TranslateLoader {
    return new TranslateLoaderService(this, prefix, suffix);
  }

  openDefaultBrowser(url: string): void {
    open(url);
  }

  constructor(private httpClient: HttpClient) {
    super();
    this.notificationService = new NotificationService();
  }
}
