import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment } from '../../environments/environment.prod';

import * as moment from 'moment-timezone';
import { map } from 'rxjs/operators';


@Injectable({
  providedIn: 'root'
})
export class ProvisionsService {

  selectedProv;
  //RUNNING_PERIOD : number = 7; //days
  //STOP_PERIOR_IS_EXTERNAL = 10; //days;
  //STOP_PERIOD : number = 20; //days

  constructor( private httpClient: HttpClient ) { }

  getProvisionsAdmin( filter : any ) : Observable<any> {
    // Initialize Params Object
    let params = new HttpParams();
    if ( filter ){
      params = params.append("filter", JSON.stringify(filter));
    } 
    params = params.append("select", "-path -terraformImage -updated -jobId -logFile -pendingNextAction -outputs -vmImage");
    params = params.append("populates", JSON.stringify([
      { path: 'user', select: 'displayName' },
      { path: 'destroy', select: "-user -jobId" },
      { path: 'schedule' },
      { path: '_scenarioDoc', select: "allowed24x7RunningDays allowedInnactiveDays isDivvyEnabled"},
      { path: 'deployOpts', select: "location"}
    ]));
    return this.httpClient.get(`${environment.apiVersionPath}/provisions`, { params: params }).pipe(map((provisions:any)=>{
      provisions.results.forEach(p => {
        if (!p.deployOpts){
          p.deployOpts = {"location": "East US"};
        }
        this.timeRunning(p);
      });
      return provisions;
    }));
  }

  getProvisionsByUser(userId) : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/users/${userId}/provisions`).pipe(map((provisions:any)=>{
      provisions.results.forEach(p => {
        this.timeRunning(p);
      });
      return provisions;
    }));
  }

  getProvisionById(id) : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/provisions/${id}`).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  getEvents(userId, id) : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/users/${userId}/provisions/${id}/events`);
  }

  getDestroyProvisionsAdmin() : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/destroyprovisions`);
  }


  newProvision(body, userId) : Observable<any> {
    return this.httpClient.post(`${environment.apiVersionPath}/users/${userId}/provisions`, body).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  delProvision(id, userId):  Observable<any> {
    return this.httpClient.delete(`${environment.apiVersionPath}/users/${userId}/provisions/${id}`);
  }

  updateProvisionAdmin(id, patch):  Observable<any> {
    return this.httpClient.put(`${environment.apiVersionPath}/provisions/${id}`, patch).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  updateProvisionUser(id, userId, patch):  Observable<any> {
    return this.httpClient.put(`${environment.apiVersionPath}/users/${userId}/provisions/${id}`, patch).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  newDestroy(id, userId) : Observable<any> {
    return this.httpClient.post(`${environment.apiVersionPath}/users/${userId}/provisions/${id}/destroy`, null);
  }

  getDestroyProvisions(userId) : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/users/${userId}/destroyprovisions`);
  }

  /*
  getCombinedProvisions(userId): Observable<any> {
    return forkJoin(this.getProvisionsByUser(userId), this.getDestroyProvisions(userId))
  }

  getCombinedProvisionsAdmin(): Observable<any> {
    return forkJoin(this.getProvisionsAdmin(), this.getDestroyProvisionsAdmin())
  }*/


  getProvisionLogs(id) : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/provisions/${id}/logs`, {responseType: 'text'});
  }

  getDestroyLogs(id) : Observable<any> {
    return this.httpClient.get(`${environment.apiVersionPath}/destroyprovisions/${id}/logs`, {responseType: 'text'});
  }

  stopVms(id, userId, patch): Observable<any> {
    return this.httpClient.post(`${environment.apiVersionPath}/users/${userId}/provisions/${id}/deallocatevms`, patch).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  abort(id, userId): Observable<any> {
    return this.httpClient.post(`${environment.apiVersionPath}/users/${userId}/provisions/${id}/abort`, null);
  }

  startVms(id, userId): Observable<any> {
    return this.httpClient.post(`${environment.apiVersionPath}/users/${userId}/provisions/${id}/startvms`, null).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  extend(id, userId): Observable<any> {
    return this.httpClient.post(`${environment.apiVersionPath}/users/${userId}/provisions/${id}/extend`, null).pipe(map((p:any)=>{
      this.timeRunning(p);
      return p;
    }));
  }

  setSelectedProv(provision : any) : void {
    if ( provision ) {
      this.selectedProv = provision;
    } else {
      this.selectedProv = null;
    }
  }

  getSelectedProv() : any {
    return this.selectedProv;
  }

  timeRunning(p) : void {
    if (!p.statusVms) {
      return;
    }
    let now = new Date();
    let runningFromTime = p.runningFrom? new Date(p.runningFrom).getTime() : new Date(p.created).getTime();
    let totalRunningTime = p.timeRunning*1000*60;

    if (p.statusVms !== 'Stopped' && p.statusVms !== 'Starting' && !p.isDestroyed) {
      totalRunningTime = totalRunningTime + Math.abs(now.getTime() - runningFromTime);
    }
    
    
    let durationRunningLeft;
    if ( !p.isDestroyed && p.statusVms !== 'Stopped' && p.schedule && !p.schedule.is24x7 ) {
      let split = p.schedule.localeShutdownTime.split(":");
      let runningToDate = new Date();
      runningToDate.setHours(split[0], split[1]);
      durationRunningLeft = moment.duration(runningToDate.getTime() - now.getTime())
    } else {
      // Is 24x7
      let runningFromDate = new Date(runningFromTime);
      var runningPeriodMils = p._scenarioDoc.allowed24x7RunningDays*24*60*60*1000;
      runningFromDate.setTime(runningFromDate.getTime()+runningPeriodMils);   
      durationRunningLeft = moment.duration(runningFromDate.getTime() - now.getTime());
    }
    
    let duration = moment.duration(totalRunningTime);
    let runningDays = Math.floor(duration.asDays());
    let runningHours = duration.hours();
    let runningAsHours = Math.floor(duration.asHours());
    let runningMinutes = duration.minutes();

    
    p.runningAsDays = (runningDays? (runningDays+"d "):"") + (runningHours? runningHours+"h ": "") + runningMinutes+"m";
    p.runningAsHours = (runningAsHours? runningAsHours+"h ": "")+runningMinutes+"m";

    let autoshutdownDays = Math.abs(Math.floor(durationRunningLeft.asDays()));
    let autoshutdownHours = durationRunningLeft.hours();
    let autoshutdownAsHours = Math.floor(durationRunningLeft.asHours());
    if ( autoshutdownAsHours < 0 ) {
      autoshutdownAsHours = (24 + autoshutdownAsHours);
    }
    let autoshutdownMinutes = durationRunningLeft.minutes();
    if ( autoshutdownMinutes < 0 ) {
      autoshutdownMinutes = 60 + autoshutdownMinutes;
    }
    p.autoshutdownAsDays = (autoshutdownDays? (autoshutdownDays+"d "):"") + (autoshutdownHours? autoshutdownHours+"h ": "") + autoshutdownMinutes+"m";
    p.autoshutdownAsHours = (autoshutdownAsHours? autoshutdownAsHours+"h ": "")+autoshutdownMinutes+"m";
    
    if ( (p.statusVms === 'Stopped' || p.statusVms === 'Starting') && !p.isDestroyed ) {
      let autoDestroyDate = new Date(p.stoppedFrom);
      if (p.isExternalAccess){
        autoDestroyDate.setTime(autoDestroyDate.getTime() + (p._scenarioDoc.allowedInnactiveDays/2)*24*60*60*1000);
      } else {
        autoDestroyDate.setTime(autoDestroyDate.getTime() + p._scenarioDoc.allowedInnactiveDays*24*60*60*1000);
      }
      let autoDestroy = autoDestroyDate.getTime() - now.getTime();
      let durationStop = moment.duration(autoDestroy);
      let autoDestroyDays = Math.floor(durationStop.asDays());
      let autoDestroyHours = durationStop.hours();
      let autoDestroyAsHours = Math.floor(durationStop.asHours())
      let autoDestroyMinutes = durationStop.minutes();

      p.autoDestroyAsDays = (autoDestroyDays? (autoDestroyDays+"d "):"") + (autoDestroyHours? autoDestroyHours+"h ": "") + autoDestroyMinutes+"m";
      p.autoshutdownAsHours = (autoDestroyAsHours? autoDestroyAsHours+"h ": "")+autoDestroyMinutes+"m";

      let inactiveDate = new Date(p.stoppedFrom);
      let inactive = Math.abs(inactiveDate.getTime() - now.getTime());
      let durationInactive = moment.duration(inactive);
      let inactiveDays = Math.floor(durationInactive.asDays());
      let inactiveHours = durationInactive.hours();
      let inactiveAsHours = Math.floor(durationInactive.asHours());
      let inactiveMinutes = durationInactive.minutes();

      p.inactiveAsDays = (inactiveDays? (inactiveDays+"d "):"") + (inactiveHours? inactiveHours+"h ": "") + inactiveMinutes+"m";
      p.inactiveAsHours = (inactiveAsHours? inactiveAsHours+"h ": "")+inactiveMinutes+"m";
    }
    
  }

  addZero(i) : any {
    if (i < 10) {
      i = "0" + i;
    }
    return i;
  }

  getUTCTimes(schedule, timezone) : any {
    var dateStartup = moment.tz(timezone);
    var dateShutdown = moment.tz(timezone);
    dateStartup.set({
      hour:   schedule.startupTime.hour,
      minute: schedule.startupTime.minute,
      second: 0
    });
    dateShutdown.set({
      hour:   schedule.shutdownTime.hour,
      minute: schedule.shutdownTime.minute,
      second: 0
    });
    return {
      startupTime: dateStartup.utc().format("H:mm"), 
      shutdownTime: dateShutdown.utc().format("H:mm"),
      tagStartup: this.addZero(dateStartup.utc().format("H")) + dateStartup.utc().format("mm"),
      tagShutdown: this.addZero(dateShutdown.utc().format("H")) + dateShutdown.utc().format("mm"),
      timezoneOffset: moment.tz(timezone).utcOffset(),
      timezone: timezone
    }
  }

}
