import {ChangeDetectorRef, Component, Input, ViewChild} from '@angular/core';
import {interval, Subscriber, Subscription} from "rxjs";
import {HttpClient, HttpHeaders} from "@angular/common/http";
import {AbstractControl, ValidatorFn, Validators} from "@angular/forms";
import {Location} from '@angular/common';
import {COOKIE} from "../../login/utils/helper.class";
import {Router} from "@angular/router";
import {properties} from "../../../../environments/environment";
import {delay, repeat, startWith, switchMap} from "rxjs/operators";
import {StringUtils} from "../string-utils.class";
import {HelperFunctions} from "../HelperFunctions.class";
import {FullScreenModalComponent} from "../modal/full-screen-modal/full-screen-modal.component";
import {AlertModal} from "../modal/alert";
declare var UIkit;

@Component({
  selector: 'egi-transfer-data',
  templateUrl:'./transferData.component.html' ,
  styles:[`
      /*Arrow*/
      /*.source:first-child::after {
          content: "";
          font-size: 20px;
          font-weight: 600;
          text-align: center;
          padding-bottom: 5%;
          position: absolute;
          background-image: url('/assets/arrow.svg');
          right: -16%;
          top: 33%;
          width: 20%;
          background-size: contain;
          background-repeat: no-repeat;
          background-position: bottom;
      }*/
  `]
})
export class EGIDataTransferComponent {
  @Input() isMobile: boolean = false;
  subscriptions = [];
  statusSub: Subscription[] = [];
  accessToken =  null;
  @Input() dois;
  loginURL = properties.eoscDataTransferLoginUrl;
  sourceUrls = [];
  selectedSourceUrl = null;
  destinationUrl = ""; 
  destinationAuthUser = "";
  destinationAuthPass = "";
  destinationPath = "";   
  destinationOptions =  null;//properties.eoscDataTransferDestinations.map(dest => {return {"label": dest.destination, "value": dest}});
  selectedDestination:{ kind: string, destination: string, description: string, authType: 'token' | 'password' | 'keys',
    protocol: string, canBrowse: boolean, transferWith: string} = null;
  folders = {};
  files = {};
  requests: number = 0;
  downloadElements = null;
  @Input() isOpen = false;
  // @Input() selectedDestinationId = "dcache";
  @ViewChild('egiTransferModal') egiTransferModal: AlertModal;
  @ViewChild('egiTransferFsModal') egiTransferFsModal: FullScreenModalComponent;
  APIURL =  properties.eoscDataTransferAPI;
  // status: "loading" | "success" | "errorParser" | "errorUser" | "errorTransfer" | "init"  | "canceled" = "init";
  status: "unused" | "staging" | "submitted" | "active" | "succeeded" | "partial" |  "failed" | "canceled" | "errorParser" | "errorUser" | "init" = "init";

  // unused("unused"),
  // active("active"),
  // succeeded("succeeded"),
  // failed("failed"),
  // canceled("canceled");

  message;
  doiPrefix = properties.doiURL;
  pathValidators = [Validators.required, this.pathValidator() /*StringUtils.urlValidator()*/];
  // URLValidators = [Validators.required,   StringUtils.urlValidator()];
  URLValidators = [Validators.required];
  jobId =  null;
  statusMessage = null;
  jobStatus;

  privacyAccepted: boolean = false;

  public hostnameRegex = '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|' +
    '[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\.[^\s]{2,}|' +
    '[a-zA-Z0-9]+\.[^\s]{2,}|' +
    '[a-zA-Z0-9]+\.[^\s]{2,}'

  constructor(private http: HttpClient, private location: Location,  private _router: Router, private cdr: ChangeDetectorRef) {

  }

  ngOnInit() {
    this.URLValidators = [Validators.required, Validators.pattern(this.hostnameRegex)];
  }

  ngAfterViewInit() {
    if(this.isOpen && typeof document !== 'undefined'){
      this.open();
    }
  }

  ngOnDestroy() {
    this.subscriptions.forEach(subscription => {
      if (subscription instanceof Subscriber) {
        subscription.unsubscribe();
      }
    });
   this.statusSub.forEach(sub => {
      if(sub instanceof Subscriber) {
        sub.unsubscribe();
      }
    });

  }
  open(){
    this.accessToken = COOKIE.getCookie("EGIAccessToken");
    if(this.accessToken) {
      // if (this.selectedDestinationId) {
      //   for (let option of this.destinationOptions) {
      //     if (this.selectedDestinationId == option.value.destination) {
      //       this.selectedDestination = option.value;
      //     }
      //   }
      // } else {
      //   this.selectedDestination = this.destinationOptions[0].value;
      // }

      let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
      this.subscriptions.push(this.http.get(this.APIURL + "/storage/types", {headers: headers}).subscribe(
        (res: Array<any>) => {
          this.destinationOptions =  res.map(dest => {return {"label": dest.description, "value": dest}});
          this.selectedDestination = res[0];
        }
      ));


      for (let doi of this.dois) {
          this.sourceUrls.push(this.doiPrefix + doi);
      }
      try {
        this.sourceUrls.sort(function (a, b) {
          return Number(b.split("zenodo.")[1]) - Number(a.split("zenodo.")[1]);
        });
      } catch (e) {
      }

      this.selectedSourceUrl = this.sourceUrls[0];

      this.parse();
    }
    this.isOpen = true;
    this.init();

    if(!this.isMobile) {
      this.egiTransferModal.stayOpen = true;
      // this.egiTransferModal.back = true;
      this.egiTransferModal.cancelButton = false;
      this.egiTransferModal.okButton = true;
      this.egiTransferModal.okButtonText = ">> Transfer";
      this.egiTransferModal.alertTitle = "EOSC Data Transfer";
      if(typeof document !== 'undefined') {
        this.egiTransferModal.open();
      }
    } else {
      this.egiTransferFsModal.back = false;
      this.egiTransferFsModal.cancelButton = true;
      this.egiTransferFsModal.okButton = false;
      // this.egiTransferFsModal.okButtonText = ">> Transfer";
      this.egiTransferFsModal.title = "EOSC Data Transfer";
      if(typeof document !== 'undefined') {
        this.egiTransferFsModal.open();
      }
    }
  }
  close(){
    if(this.isOpen) {
      this.isOpen = false;
      if(!this.isMobile) {
        this.egiTransferModal.cancel();
      } else {
        this.egiTransferFsModal.cancel();
      }
    }
    // this.downloadElements = [];
    this.init();
    if(this._router.url.indexOf("&egiTransfer")){
      this.location.go(this._router.url.split("&egiTransfer")[0]);
    }
    
  }
  init(){
    this.destinationPath = "";
    // this.selectedDestination = this.destinationOptions[0].value;
    this.selectedSourceUrl = this.sourceUrls[0];
    this.message = null;
    this.status = "init";
    this.jobId = null;
    // this.statusMessage = null;
    this.statusMessage = "primary";
    this.requests = 0;
    this.folders = {};
    this.files = {};
    this.statusSub.forEach(sub => {
      if(sub instanceof Subscriber) {
        sub.unsubscribe();
      }
    });
  }
  checkin(){
    window.location.href = this.loginURL+"?redirect="+ encodeURIComponent(window.location.href + (window.location.href.indexOf("&egiTransfer=t")!=-1?"":"&egiTransfer=t"));

  }
  parse(){
    this.status = "active";
    this.message = null;
    this.downloadElements = [];
    let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
        this.subscriptions.push(this.http.get(this.APIURL + "/parser?doi=" + encodeURIComponent(this.selectedSourceUrl), {headers: headers}).subscribe(
          res => {
            // res['elements'].forEach(element => {
            //   if(element.downloadUrl && element.name) {
            //     this.downloadElements.push(element);
            //   }
            // })
              this.downloadElements= res['elements']
            // console.log(this.downloadElements)
              this.status = "init";
          }, error => {
            this.status = "errorParser";
            this.message = error.error && error.error.id && error.error.id == 'doiNotSupported'?'DOI not supported.':( error.error && error.error.description && error.error.description? (error.error.description+'.'):'Error parsing information.') ;
            this.statusMessage = "danger";
            this.cdr.detectChanges();
            HelperFunctions.scrollToId("transferAlert");
          /*  UIkit.notification(this.message, {
              status: 'error',
              timeout: 3000,
              pos: 'bottom-right'
            });*/

          }
        ));

  }

  transfer() {
    // console.log(this.selectedDestination)
  this.status = "active";
  this.message = "";
  let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});

  this.subscriptions.push(this.http.get(this.APIURL + "/user/info?dest="+this.selectedDestination.destination, {headers: headers}).subscribe(
    res => {
      // console.log(res)
    let body = {
      "files": [],
      "params": {
        "priority": 0,
        "overwrite": false,
        "retry": 3
      }
    };

      // console.log(this.selectedDestination)
    for (let element of this.downloadElements) {
     let file = {
        "sources": [element['downloadUrl']],
        "destinations": [(this.selectedDestination.protocol+"://") + this.destinationUrl + this.destinationPath + (this.destinationPath.endsWith("/") ? "" : "/") + ((element.path && element.path != "/") ? element.path : "") + element.name],

      };
     //TODO priority? checksum? filesize?
     //  "filesize": element['size']
     body.files.push(file);
    }

    let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
    if(this.selectedDestination.authType != "token" && this.destinationAuthPass.length > 0 && this.destinationAuthUser.length > 0){
      headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken,
        'Authorization-Storage': btoa(this.destinationAuthUser + ':' + this.destinationAuthPass)});
    }
    this.subscriptions.push(this.http.post(this.APIURL + "/transfers" ,body, {headers: headers}).subscribe(
      res => {
        // console.log(res)
        // UIkit.notification('Data transfer has began! ', {
        //   status: 'success',
        //   timeout: 6000,
        //   pos: 'bottom-right'
        // });

        this.jobId = res['jobId'];
        this.getStatus();
        this.status = "active";
        this.statusMessage = "primary";

        // this.egiTransferModal.okButton = false;
        this.message = `
            <!--div class="uk-text-large uk-margin-bottom">Data transfer has began!</div-->
            <div>Transfer of  ` + this.downloadElements.length + ` files to `+this.selectedDestination.description+` has began.`;
        /*this.message += ` <div class=" uk-overflow-auto uk-height-xsmall" >
            <ul>           
`;
        // TODO LATER we can call status for each file and see if the transfer has been complete
        for(let element of this.downloadElements){
          // console.log(element)
          // this.message += ` <li> <a href="`+ this.selectedDestination.webpage + this.destinationPath + element.name + `" target="_blank">`+ element.name+ `</a></li>  `;
          this.message += ` <li>`+ element.name+ `</li>  `;
        }
        this.message += `
        </ul>  
        </div>
          </div>`*/
        this.message += `
       
          </div>`

        this.cdr.detectChanges();
        HelperFunctions.scrollToId("transferAlert");

        // this.getStatus(true)

      }, error => {
        this.status = "failed";
        this.message = "Files could not be transfered.";
        this.statusMessage = "danger";
        this.cdr.detectChanges();
        HelperFunctions.scrollToId("transferAlert");
        // UIkit.notification("Couldn't transfer files", {
        //   status: 'error',
        //   timeout: 6000,
        //   pos: 'bottom-right'
        // });

      }
    ));
    }, error => {
      this.status = "errorUser";
      this.message = "User cannot be authenticated.";
      this.statusMessage = "danger";
      this.cdr.detectChanges();
      HelperFunctions.scrollToId("transferAlert");
      // UIkit.notification("User can't be authenticated!", {
      //   status: 'error',
      //   timeout: 6000,
      //   pos: 'bottom-right'
      // });

    }
  ));
  }
  
  getStatus(updateTransferMessage:boolean = false){
    if(this.jobId){
      this.requests = 10;
      this.statusSub.forEach(sub => {
        if(sub instanceof Subscriber) {
          sub.unsubscribe();
        }
      });
      
      let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
      let source = this.http.get(this.APIURL + "/transfer/" +this.jobId , {headers: headers}).pipe(delay(5000));

      let source2 = interval(5000)  // request status every 5 secs
        .pipe(
          startWith(2000), // first call after 2 secs
          switchMap(() => this.http.get(this.APIURL + "/transfer/" +this.jobId , {headers: headers}))
        );

       this.statusSub.push(source2.subscribe((res: any) => {
	   this.requests--;
           if(this.status != res.jobState) {
             this.status = res.jobState;
             this.jobStatus = res;
             this.message = `
              <!--div class="uk-text-large uk-margin-bottom">Data transfer has began!</div-->
              <div>Transfer of  ` + this.downloadElements.length + ` files to  ` + this.selectedDestination.description + ` has began.`;
             /*this.message += ` <div class=" uk-overflow-auto uk-height-xsmall" >
                 <ul>
     `;
             // TODO LATER we can call status for each file and see if the transfer has been complete
             for(let element of this.downloadElements){
               // console.log(element)
               // this.message += ` <li> <a href="`+ this.selectedDestination.webpage + this.destinationPath + element.name + `" target="_blank">`+ element.name+ `</a></li>  `;
               this.message += ` <li>`+ element.name+ `</li>  `;
             }
             this.message += `
             </ul>
             </div>
               </div>`*/
             this.message += `
         
            </div>`;
	     this.message += "<div>Transfer status: <b>"+res.jobState+"</b>.</div>";
             this.statusMessage = "primary";
             //this.statusMessage = res['jobState'] + (res['reason'] ? (" :" + res['reason']) : "");
             if(this.status == "partial") {
		this.message = "At least one of the selected files was successfully transfered.";
		this.statusMessage = "success";
		//this.statusSub.unsubscribe();
		this.statusSub.forEach(sub => {
		  if(sub instanceof Subscriber) {
		    sub.unsubscribe();
		  }
		});
		this.requests = 0;
	     } else if(this.status == "succeeded") {
               this.message = "Transfer successfully completed!";
               this.statusMessage = "success";
               //this.statusSub.unsubscribe();
	       this.statusSub.forEach(sub => {
		 if(sub instanceof Subscriber) {
	           sub.unsubscribe();
		 }
	       });
	       this.requests = 0;
               // UIkit.notification('Transfer successfully completed! ', {
               //   status: 'success',
               //   timeout: 6000,
               //   pos: 'bottom-right'
               // });
             } else if(this.status == "failed") {
               this.message = "Transfer failed.";
               this.statusMessage = "danger";
               //this.statusSub.unsubscribe();
	       this.statusSub.forEach(sub => {
		 if(sub instanceof Subscriber) {
		   sub.unsubscribe();
		 }
	       });
	       this.requests = 0;
               // UIkit.notification('Transfer failed', {
               //   status: 'danger',
               //   timeout: 6000,
               //   pos: 'bottom-right'
               // });
             } else if(this.requests <= 0 || (this.status != "active" && this.status != "submitted" && this.status != "staging")) {
               this.message = "Transfer status: <b>"+this.status+"</b>.";
               this.statusMessage = "warning";
               //this.statusSub.unsubscribe();
	       this.statusSub.forEach(sub => {
		 if(sub instanceof Subscriber) {
		   sub.unsubscribe();
		 }
	       });
	       this.requests = 0;
               // UIkit.notification('Transfer completed with status: '+this.status, {
               //   status: 'warning',
               //   timeout: 6000,
               //   pos: 'bottom-right'
               // });
             }
           }
	   if(this.requests <= 0) {
               this.message = "Transfer status: <b>"+this.status+"</b>.";
               this.statusMessage = "warning";
               //this.statusSub.unsubscribe();
	       this.statusSub.forEach(sub => {
		 if(sub instanceof Subscriber) {
		   sub.unsubscribe();
		 }
	       });
	   }
        }, error => {
           this.status = "failed";
           this.message = "Status of the transfer could not be retrieved.";
           this.statusMessage = "danger";
           this.statusSub.forEach(sub => {
	     if(sub instanceof Subscriber) {
		sub.unsubscribe();
	     }
	  });
	  this.requests = 0;
           // UIkit.notification("Couldn't get status", {
          //   status: 'error',
          //   timeout: 6000,
          //   pos: 'bottom-right'
          // });

        }
      ));
    }
  }


  cancel(){
    if(this.jobId){
      let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
      this.subscriptions.push(this.http.delete(this.APIURL + "/transfer/" +this.jobId , {headers: headers}).subscribe(
        res => {
          this.jobStatus = res;
          this.statusMessage = res['jobState'] + (res['reason']?(" :" + res['reason']):"");
          this.jobId = null;
          this.status = "canceled";
        }
      ));
    }
  }
  hasBrowse(){
      let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
      this.subscriptions.push(this.http.get(this.APIURL + "/storage/info?dest="+this.selectedDestination.destination+"&seUrl="+encodeURIComponent((this.selectedDestination.protocol+'://') + this.destinationUrl + this.destinationPath) , {headers: headers}).subscribe(
        res => {
          console.log(res);
        }
      ));
    
  }
  getFolder(folderPath){
    //TODO is this necessary?
    let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
    this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder?dest="+this.selectedDestination.destination+"&seUrl="+encodeURIComponent((this.selectedDestination.protocol + '://') + this.destinationUrl + folderPath) , {headers: headers}).subscribe(
      res => {
        this.folders[folderPath]= res;
        this.folders[folderPath]['isOpen'] = true;
      }
    ));

  }
  browseFolder(folderPath){
    if(this.folders[folderPath]){
      this.folders[folderPath].isOpen = !this.folders[folderPath].isOpen;
      return;
    }
    this.getFolder(folderPath);
    let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
    this.subscriptions.push(this.http.get(this.APIURL + "/storage/folder/list?dest="+this.selectedDestination.destination+"&folderUrl="+encodeURIComponent((this.selectedDestination.protocol + '://') + this.destinationUrl + folderPath) , {headers: headers}).subscribe(
      res => {
        this.files[folderPath]= res['elements'];
      }
    ));

  }
  createFolder(){
    let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
    this.subscriptions.push(this.http.post(this.APIURL + "/storage/folder?dest="+this.selectedDestination.destination+"&seUrl="+
      encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe(
      res => {
        console.log(res);
      }
    ));

  }
  deleteFolder(){

    let headers = new HttpHeaders({'Authorization': 'Bearer '+this.accessToken});
    this.subscriptions.push(this.http.delete(this.APIURL + "/storage/folder?dest="+this.selectedDestination.destination+"&seUrl="+encodeURIComponent(this.destinationUrl + this.destinationPath + "test1/") , {headers: headers}).subscribe(
      res => {
        console.log(res);
      }
    ));

  }
  private parseFilename(url){
    let filename = url.split("/")[url.split("/").length - 1];
    return filename.split("?")[0];
  }
  pathValidator(): ValidatorFn {
    return (control: AbstractControl): { [key: string]: string } | null => {
      if (!this.validatePath()) {
        return {'error': 'Path should start with "/"'};
      }
      return null;
    }
  }
  validatePath():boolean {
      // let exp1 = /^\/([A-z0-9-_+]+\/?)*$/g;
    // let exp1 = /^\/([A-z0-9-_]+[+\/]?)*$/;
      return (this.destinationPath.length > 0  && this.destinationPath.startsWith("/"))
    
  }

  validateDestinationUrl():boolean {
    return (this.destinationUrl.length > 0 && new RegExp(this.hostnameRegex).test(this.destinationUrl));
  }

  // public sourceUrlValidators() {
  //   this.URLValidators = [];
  //   this.URLValidators = [Validators.required, Validators.pattern(this.hostnameRegex)];
  // }
}
