import { Component, HostListener, OnDestroy } from '@angular/core';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
import { Subscription } from 'rxjs';
import { DriveFile } from 'src/app/components/resource-page/drive-window/drive-layout/drive-file';
import { NanoService, RequestSession } from '../../nano/nano.service';
import { BlobService } from '../../services/blob.service';
import { CordovaService } from '../../services/cordova.service';
import { DialogService } from '../../services/dialog.service';
import { DownloadManagerService } from '../../services/download-manager-service';
import { SnackBarService } from '../../services/snackbar.service';
import { MediaViewerService } from '../media-viewer.service';

@Component({
  selector: 'app-image-viewer',
  templateUrl: './image-viewer.component.html',
  styleUrls: ['./image-viewer.component.scss'],
})
export class ImageViewerComponent implements OnDestroy {
  private sub: Subscription;
  public file: DriveFile;
  public path: string;
  public roomId: string;
  public currentChunk: number = 0;
  public maxChunk: number;
  public loaded: boolean = false;
  public data: Uint8Array;
  public objectURL: string;
  public safeUrl: SafeUrl;
  public opened: boolean = false;
  public error: boolean = false;
  private session: RequestSession;
  public thumbnailSafeUrl: SafeUrl;
  private thumbnailBlobUrl;

  constructor(
    private mediaViewerService: MediaViewerService,
    private sanitizer: DomSanitizer,
    private cordovaService: CordovaService,
    private dialogeService: DialogService,
    private nanoService: NanoService,
    private blobService: BlobService,
    private snackbarService: SnackBarService,
    private downloadManagerService: DownloadManagerService
  ) {
    this.sub = this.mediaViewerService.subscribeImageShow({
      next: (res) => {
        // init call
        this.reset(); // close the last session
        this.opened = true;

        // onPopState handling
        // removes last popstate eventlistener
        window.removeEventListener('popstate', this.popStateCallback);
        // history push
        history.pushState(null, null, window.location.href);
        // set new popstate eventlistener
        window.addEventListener('popstate', this.popStateCallback);

        this.file = res.file;
        this.path = res.path;
        this.roomId = res.roomId;

        this.thumbnailBlobUrl = this.blobService.createObjectURL(
          this.blobService.new([res.file.thumbnail]) /*res.file.mime*/
        );
        this.thumbnailSafeUrl = this.sanitizer.bypassSecurityTrustUrl(this.thumbnailBlobUrl);

        this.nanoService.getFile(
          res.roomId,
          res.path,
          null, // force to use the BlobSaver
          (response) => {
            this.data = response;
            if (this.objectURL) {
              this.blobService.revokeObjectURL(this.objectURL);
            }
            this.objectURL = this.blobService.createObjectURL(
              this.blobService.new([this.data]) /*res.file.mime*/
            );
            this.safeUrl = this.sanitizer.bypassSecurityTrustUrl(this.objectURL);
            this.loaded = true;
            this.session = null;
          },
          (err) => {
            this.error = true;
            console.error('err', err);
          },
          (current, max, session) => {
            this.loaded = false;
            this.currentChunk = current;
            this.maxChunk = max;
            this.session = session;

            try {
              // need some chunk for the half-done preview
              if (current > 2 && session && session.payloadParts) {
                let chunks = [];
                for (let key in session.payloadParts['payloads']) {
                  chunks.push(session.payloadParts['payloads'][key].chunk.fc);
                }
                if (this.objectURL) {
                  this.blobService.revokeObjectURL(this.objectURL);
                }
                this.objectURL = this.blobService.createObjectURL(
                  this.blobService.new(chunks) /*res.file.mime*/
                );
                this.safeUrl = this.sanitizer.bypassSecurityTrustUrl(this.objectURL);
              }
            } catch (e) {
              console.warn('err', e);
            }
          }
        );
      },
      error: (err) => {
        this.error = true;
        console.error('err', err);
      },
    });
  }

  // callback fired on popstate event - handles 'back' event
  private popStateCallback = () => {
    if (this.opened) {
      this.close(false); // false param indicates that it should not use history.back() in close()
    }
  };

  ngOnDestroy(): void {
    if (this.sub) {
      this.sub.unsubscribe();
    }
    window.removeEventListener('popstate', this.popStateCallback);
  }

  private reset() {
    this.data = null;
    this.loaded = false;
    this.error = false;
    this.safeUrl = null;
    this.currentChunk = 0;
    this.maxChunk = 1;
    if (this.session) {
      this.session.pause();
      this.session = null;
    }
    if (this.objectURL) {
      this.blobService.revokeObjectURL(this.objectURL);
      this.blobService.revokeObjectURL(this.thumbnailBlobUrl);
      this.objectURL = null;
    }
  }

  /**
   * closes image-viewer modal
   * @param goBack steps back with histor when given. Should call with 'false' when 'back' button is pressed (location.popState event)
   */
  public close(goBack: boolean = true) {
    if (goBack) {
      history.back();
    }
    this.opened = false;
    this.reset();
  }

  public clickOutside(event) {
    // close when clicked on the background
    if (event.target && event.target.id == 'media-cont') {
      this.close();
    }
  }

  @HostListener('document:keydown.escape', ['$event']) onKeydownHandler(event: KeyboardEvent) {
    if (this.opened) {
      this.close();
    }
  }

  public download() {
    console.log('this', this);
    if (this.cordovaService.isOnApp()) {
      this.cordovaService
        .getFileWriter(this.file.fullName)
        .then((fw) => {
          fw.write(this.data)
            .then(() => {
              this.snackbarService.showSnackbar(marker('Download is done'));
            })
            .catch((err) => {
              console.error('file save err', err);
              this.dialogeService.openAlertDialog(
                marker('File save error'),
                marker('Could not save the file'),
                err
              );
            })
            .finally(() => {
              fw.close();
            });
        })
        .catch((err) => {
          console.error('file save creator err', err);
          this.dialogeService.openAlertDialog(
            marker('File saver creator error'),
            marker('Could not save the file'),
            err
          );
        });
    } else {
      var a;
      a = document.createElement('a');
      a.href = this.objectURL;
      a.download = this.file.fullName;
      document.body.appendChild(a);
      a.style = 'display: none';
      a.click();
      a.remove();
    }

    let refForFile = this.downloadManagerService.createDefaultFileManagerType(
      this.file,
      this.roomId,
      this.path
    );
    refForFile.done = true;
    this.downloadManagerService.getFileList().push(refForFile);
  }
}
