import { Component, OnInit, ViewChild,OnChanges } from '@angular/core';
import { Chart, ChartOptions, ChartType, ChartDataSets } from 'chart.js';
import { Label, BaseChartDirective } from 'ng2-charts';
import { MeasuresService } from 'src/app/services/measures.service';
import { PlantsService } from 'src/app/services/plants.service';
import { LogsService } from 'src/app/services/logs.service';
import { OrganizationsService } from '@app/services/organizations.service';

import { ActivatedRoute } from '@angular/router';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table';
import Swal from 'sweetalert2';
import { HttpClient } from '@angular/common/http';
import { formatDate, DatePipe } from '@angular/common';

import {AngularMyDatePickerDirective,IAngularMyDpOptions, IMyDateModel} from 'angular-mydatepicker';
import printJS from 'print-js'
import { ExportType,ExcelOptions, Options } from 'mat-table-exporter';
import * as $ from "jquery";

@Component({
  selector: 'app-assets',
  templateUrl: './assets.component.html',
  styleUrls: ['./assets.component.scss']
})

export class AssetsComponent implements OnInit {
  exportExcel = ExportType.XLSX;
  exportCSV = ExportType.CSV;
  exportJSON = ExportType.JSON;
  ExcelOptions:ExcelOptions = {fileName:'data-Medidores', sheet: 'Hoja 1', Props: {Author: 'INVERLEC'}}
  CSVOptions:Options = {fileName:'data-Medidores'}
  JSONOptions:Options = {fileName:'data-Medidores'}
  title = "Plantas";

  // General var declarations
  assetID:string;
  listAssets:any;
  eProduced:any;
  error:boolean;
  errorMessage:string;
  errortest:any;
  metersKeys:any;
  metersValues:any;
  view:string;
  energyDay=0;
  energyWeek=0;
  energyMonth=0;
  energyYear=0;
  environment:any;
  environmentCO2:any;
  environmentHouse:any;
  environmentFuel:any;
  isActive:[boolean,boolean,boolean,boolean,boolean,boolean,boolean,boolean,boolean]; //Activated param (chart)
  chartActive:[boolean,boolean,boolean,boolean]
  initialLoad: boolean = true;
  metersInstalled:boolean = true;

  // For daterange
  daysLabels:any = {su: 'Dom', mo: 'Lun', tu: 'Mar', we: 'Mie', th: 'Jue', fr: 'Vie', sa: 'Sab'};
  monthsLabels:any = { 1: 'Ene', 2: 'Feb', 3: 'Mar', 4: 'Abr', 5: 'May', 6: 'Jun', 7: 'Jul', 8: 'Ago', 9: 'Sep', 10: 'Oct', 11: 'Nov', 12: 'Dic' };
  todayBtnTxt:string = 'Hoy';
  myDpOptions: IAngularMyDpOptions = {
    dateRange: false,
    dateFormat: 'dd/mm/yyyy',
    dayLabels: this.daysLabels,
    monthLabels: this.monthsLabels,
  };
  myDateInit: boolean = true;
  model: IMyDateModel = null;

  // For MatDataTable
  metersData:any;
  initialDate:any;
  tableData: any;
  showTable: boolean;
  displayedColumns: any;
  tableData2: any[];
  array1: any[];
  array2: any[];
  array3: any[];
  dataSource = new MatTableDataSource(this.tableData2);
  dataSourcePrint = new MatTableDataSource(this.tableData2);
  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
  @ViewChild(MatSort, { static: true }) sort: MatSort;

  // For chartjs
  chartjs:boolean;
  chart1: Chart;
  chart1Type: string;
  barChartColors:any = ['#5f86b0','#a9d0ea', '#00a65a', '#a7c957', '#f2e8cf', '#3c8dbc', '#f56954', '#ee964b']
  borderChartColors:any = ['#4573a5','#a2cae4', '#018247', '#91b43d', '#d3cbb7', '#539dc8', '#e4604c', '#d38d51']
  public barChartType: ChartType;
  public barChartLegend:boolean;
  public barChartLabels: Label[];
  public barChartOptions: ChartOptions;
  public barChartData: ChartDataSets[];
  @ViewChild("baseChart",null) chart: BaseChartDirective;
  city: any;
  total_savings: any;
  last_day_savings: number;
  savings_logs: any;
  savings_logs_data = [];

  
  // Get selected asset
  constructor(
    private orgService: OrganizationsService, 
    private route: ActivatedRoute, 
    private plantsService: PlantsService,
    private http: HttpClient,
    private logsService: LogsService,
    private measService: MeasuresService,
    public datepipe: DatePipe) {
      
      this.route.queryParams.subscribe(params => {
        this.assetID = params['id'];
      });
      
      Swal.fire({
        allowOutsideClick: false,
        type: 'info',
        text: 'Espere por favor...'
      });
      Swal.showLoading();
  }

  ngOnInit() {
    // Default date is today and set it on a string var and initialize dateRange plugin
    this.initialDate = this.datepipe.transform(new Date(), 'yyyy-MM-dd')//.toISOString().slice(0, 10);
    if (this.myDateInit) {
      let begin: Date = new Date();
      this.model = {
        isRange: false, 
        singleDate: {
          date: {
            year: begin.getFullYear(), month: begin.getMonth() + 1, day: begin.getDate()
          }
        }
      };
    }

    // Initialize default 'clicked' options for chart button options
    this.isActive = [false, false, false, false, false, false, false, false, false];
    
    this.chartActive = [true, false, false, false];

    // Get all assets (according to user's assigned organizations)
    let plants = this.plantsService.getAllAssets().subscribe(res => {
      this.listAssets = res["data"]["assets"];
      
      // Default values for chart 
      this.view = "month";
      this.chart1Type = "bar";
      
      if (this.assetID == undefined){
        this.assetID = this.listAssets[0].id;
        this.city = this.listAssets[0].city;
      }
      else {
        this.city = this.listAssets.find(object=>object.id == this.assetID).city;
      }
  
      let tempAsset = this.listAssets.find(object=>object.id == this.assetID);

      if (tempAsset["meters_installed"].length > 0){
        this.metersInstalled = true;

        
        // Get savings produced by an asset
        this.getSavings(this.assetID);

        // Get energy produced given an asset 
        this.getEnergyProduced(this.assetID); 
        // Initialize a draw chart according to the default values
        this.getMeasureRangeChart(this.view, this.initialDate, this.assetID);
        // Get environmental data given an asset
        this.getEnvironmentalData(this.assetID);
      }
      else {
        this.metersInstalled = false;
      }


    }, (err) => {
      Swal.fire({
        type: 'error',
        title: 'Error en el servidor',
        text: err.message
      });
    });

    //this.chartjs = true;
    setTimeout(()=>{
      Swal.close();
    }, 3000);
  }
  
  // Default check asset dropdown if a value is equal to an assetID
  isSelected(){
    if(this.assetID!=undefined){
      return true;
    }
    else{
      return false;
    }
  }

  ngOnChanges() {
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
    //this.dtTrigger.next();
  }

  // Trigger again the chart with the selected assetID
  onChangeObj(event:any) {
    this.assetID = event.target.value;
    let tempAsset = this.listAssets.find(object=>object.id == this.assetID);
    this.city = tempAsset["city"];
    this.total_savings = 0;
    this.last_day_savings = 0;
    if (tempAsset["meters_installed"].length > 0){
      this.metersInstalled = true;
      this.getSavings(this.assetID);
      this.getEnergyProduced(this.assetID);
      this.getMeasureRangeChart(this.view, this.initialDate, this.assetID);
      this.getEnvironmentalData(this.assetID);
    }
    else { 

      Swal.fire({
        allowOutsideClick: false,
        type: 'info',
        text: 'Espere por favor...'
      });
      Swal.showLoading();
      setTimeout(()=>{
        Swal.close();
        this.metersInstalled = false;
        if (this.chart1 != undefined ){
          this.chart1.destroy();
        }
        this.chart1 = undefined;
        this.chart1 = new Chart('canvas', {});
    
      }, 3000);
  
    }
  }
  
  // Change the date range of the chart, according to the selected view (daily, weekly, ...)
  onDateChanged(event: IMyDateModel) {
    let endDate = `${event.singleDate.date.year}-${event.singleDate.date.month}-${event.singleDate.date.day}`;
    this.initialDate  = endDate;

    this.getMeasureRangeChart(this.view, endDate);

    
  }

  getSavings(assetID: string) {
    this.plantsService.getAssetSavings(this.assetID).subscribe( res => {
      this.total_savings = res["data"]["ahorro_total"];
      this.total_savings = +this.total_savings > 10000 ? (+this.total_savings / 1000).toFixed(3) + "k" : +this.total_savings.toFixed(2) || 0;
      this.last_day_savings = +res["data"]["ahorro_ultimas_24_horas"].toFixed(2) || 0;
    })  
  }
 

  getEnvironmentalData(assetID: string) {
    this.logsService.getAssetEnviromentalStats(assetID).subscribe(resp => {
      this.environment = resp["data"]["environmentals"];
      this.environmentCO2 = this.environment.avoided_kg_of_co2.toFixed(2); 
      this.environmentHouse = this.environment.number_of_homes.toFixed(0);
      this.environmentFuel = this.environment.number_of_crude_barrels.toFixed(2);
    });
  }

  getEnergyProduced(assetID:string){
    // Api call to get the energy summary stats of all assets in the organization
    let energy_produced = this.logsService.getEnergySummaryByAsset(assetID).subscribe(resp => {
      this.eProduced = resp["data"]["energy"];//results[1];
      this.energyDay = this.eProduced.today.total_energy_kWh || 0;
      this.energyWeek = this.eProduced.thisWeek.total_energy_kWh > 0 ? (this.eProduced.thisWeek.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisWeek.total_energy_kWh || 0
      this.energyMonth = this.eProduced.thisMonth.total_energy_kWh > 0 ? (this.eProduced.thisMonth.total_energy_kWh/1000).toFixed(2) : this.eProduced.thisMonth.total_energy_kWh || 0
      this.energyYear = this.eProduced.lifeTime.total_energy_kWh > 0 ? (this.eProduced.lifeTime.total_energy_kWh/1000).toFixed(2) : this.eProduced.lifeTime.total_energy_kWh || 0
    }, (err) => {
      Swal.fire({
        type: 'error',
        title: 'Error en el servidor',
        text: "No su pudo obtener la informacion"
      });
    });
  }

  // Draw a measure chart using chartjs, given some params, view, for daily, weekly, monthly or yearly measures;
  // measureDate, for a date range given a view and a paramID, for an specific assetID selected in the dropdown  
  getMeasureRangeChart(view:string, measureDate?:string, paramId?:string): void {
    if(this.initialLoad == false){
      Swal.fire({
        allowOutsideClick: false,
        type: 'info',
        text: 'Espere por favor...'
      });
      Swal.showLoading();
    }
    this.initialLoad = false;
    this.view = view;

    // Chart (re)initialize, to prevent double load on changing date range or views
    if (this.chart1 != undefined){
      this.chart1.destroy();
    }
    this.chart1 = undefined;
    
    let dateRange:string;
    if (measureDate === undefined){
      dateRange = this.initialDate;
    }
    else {
      dateRange = measureDate;
    }

    // Set default assetID if paramId doesn't come in the function call
    let assetId:string;
    if (paramId === undefined){
      assetId = this.listAssets[0]["id"]; // Grab the first object
    }
    else {
      assetId = paramId;
    }
    
    // Select an interval according to the API permitted param
    let interval:string;
    switch (view)
    { 

      case "day": 
        interval = "1D";
        this.isActive = [true, false, false, false, false, false, false, false, false];
        break; 
      case "week": 
        interval = "7D";
        this.isActive = [false, true, false, false, false, false, false, false, false];
        break; 
      case "WTD":
        interval = "WTD"
        this.isActive = [false, false, true, false, false, false, false, false, false];
        break;
      case "month":
        interval = "1M";
        this.isActive = [false, false, false, true, false, false, false, false, false];
        break; 
      case "MTD":
        interval = "MTD";
        this.isActive = [false, false, false, false, true, false, false, false, false];
        break;
      case "3m":
        interval = "3M";
        this.isActive = [false, false, false, false, false, true, false, false, false];
        break;
      case "12m":
        interval = "1Y";
        this.isActive = [false, false, false, false, false, false, true, false, false];
        break;
      case "YTD":
        interval = "YTD";
        this.isActive = [false, false, false, false, false, false, false, true, false];
        break;
      case "total":
        interval = "TOTAL";
        this.isActive = [false, false, false, false, false, false, false, false, true];
        break;
      default: 
    }

    this.logsService.getEnergySavingsProducedByAsset(assetId, interval, dateRange).toPromise()
    .then((res: any)=>{
      this.savings_logs = undefined;
      this.savings_logs_data = [];
      this.savings_logs = res["data"]["dataset"];
      let savingsKeys = Object.keys(this.savings_logs);
      for (let key in savingsKeys) {
        let savingDate = savingsKeys[key];
        this.savings_logs_data.push(this.savings_logs[savingDate]["ahorro"]);
      }

      
      // Get the measures according to the meters, given the params required
      this.logsService.getEnergyProducedByParams(assetId,interval,dateRange).toPromise()
      .then((data: any) => {

        this.metersData = [];      
        this.metersKeys = Object.keys(data["data"]["dataset"]);
        
        // Get all the values according to each index (meter) 
        this.metersValues = Object.values(data["data"]["dataset"]);

        /// Get the keys of those values
        let meterKeys2 = Object.keys(this.metersValues);
        this.displayedColumns= [];
        this.tableData = [];
        this.metersData.push({ "label": "AHORRO [US$]", data: this.savings_logs_data.reverse(), type: "line", backgroundColor: "#e57272", borderColor: "#ce2525", borderWidth: 2, yAxisID: 'y-axis-ahorro', fill: false})
        // The chart data object requires certain ordered params, so we itirate the returned object from the API call,
        // and build the new object with the required/needed values
        for (let prop in meterKeys2) { 
          //let label = localStorage.getItem("email") == "inverlec@grupomerelec.com" ? `INVERLEC ${prop}` : this.metersValues[prop]["label"];
          let label = this.metersValues[prop]["label"]+" [kWh]";
          let measure_values = Object.values(this.metersValues[prop]["data"].map(obj => obj.total_energy_kWh).reverse());
          this.metersData.push({"label": label, backgroundColor: this.barChartColors[prop], data: measure_values, borderColor: this.borderChartColors[prop] });
          this.tableData.push({headers: label+" [kWh]", dataValues: measure_values});
        }

        // this.metersData.push({ "label": "Ahorro", data: [10,30,30,40,30,20,15,25,30,35], type: "line", backgroundColor: "#e57272", borderColor: "#ce2525", borderWidth: 2, yAxisID: 'y-axis-ahorro',})
        // Initialization of arrays for the table view of the measure values
        this.array1 = this.array2 = this.array3 = [];

        // Loop to build an object that contains the date and each meter value from a certain asset
        // This object is required to build the datatable
        for (let prop in meterKeys2) { 
          this.array2 = [];
          //let label = localStorage.getItem("email") == "inverlec@grupomerelec.com" ? `INVERLEC ${prop}` : this.metersValues[prop]["label"];
          let quantity = Object.keys(this.metersValues[0]["data"]);
          let mvalues = Object.values(this.metersValues[prop]["data"].map(obj => obj).reverse())
          
          for (let prop2 in quantity){
            // Date insertion
            this.array3 = [];
            let columnname = `medidor${prop}`;
          
            if (+prop == 0 && mvalues[prop2] != undefined){
              let dateT = this.getDateWithFormat(this.view, mvalues[prop2]["dateMax"])
              this.array3.push(dateT);
              this.array3.push(this.savings_logs_data[prop2]);
            }
            
            if (mvalues[prop2] != undefined) { 
              this.array3.push(mvalues[prop2]["total_energy_kWh"]);
            }
            else {
              this.array3.push(0)
            }

            if (+prop == 0){
              this.array2.push(this.array3)
            }
            
            if (+prop != 0) {
              this.array1[prop2].push(this.array3[0]);
            }
          }
          if (+prop == 0){
            this.array1 = (this.array2)
            //this.array1 = [].concat.apply([], this.array1)
          }    
        }

        // According to the selected interval in the option buttons of the chart, the date is given an specific format 
        switch (view){
          case "day": 
            this.barChartLabels = this.metersValues[0]["data"].map(obj => formatDate(obj.dateMin, 'HH:mm ','es-Es','-0600')).reverse();
            break; 
          case 'week':
            this.barChartLabels = this.metersValues[0]["data"].map(obj => formatDate(obj.dateMax, 'EEEE dd','es-Es','-0600')).reverse();
            break;
          case "year":
            this.barChartLabels = this.metersValues[0]["data"].map(obj => formatDate(obj.dateMax, 'MM/yyyy','es-Es','-0600')).reverse();
            break;
          default: 
            this.barChartLabels = this.metersValues[0]["data"].map(obj => formatDate(obj.dateMax, 'dd/MM','es-Es','-0600')).reverse(); 
        }

        // Push the values to the chart object
        this.tableData.push({headers: "Ahorro[US$]"});
        this.tableData.push({headers: "Fecha/Hora", dataValues: this.barChartLabels});
        this.tableData.reverse()
        for( let v in Object.keys(this.tableData)){
          this.displayedColumns.push(this.tableData[v]["headers"]);
        }
        this.tableData2 = this.array1;
        if (this.array1.length == 0){
          $(".no-data").css('visibility', 'visible');
          $(".chart-container").css('visibility', 'hidden');
        }
        else {
          $(".no-data").css('visibility', 'hidden');
          $(".chart-container").css('visibility', 'visible');
        }

        this.dataSource.data = this.tableData2;
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.sort;

        this.dataSourcePrint.data = this.tableData2;

        this.showTable = true;
        this.chart1 = new Chart('canvas', {
          type: this.chart1Type,
          options: {
            title: {
              display: true,
            },
            tooltips: {
              mode: 'index',
              callbacks: {
                // Get the total of the energy produced in every point and show it in the hover tooltip
                label: function (tooltipItem, data) { 
                  var label = data.datasets[tooltipItem.datasetIndex].label || '';
                  var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
                  var total = 0;

                  for (var i = 1; i < data.datasets.length; i++)
                    total += +data.datasets[i].data[tooltipItem.index];

                  if (tooltipItem.datasetIndex !== data.datasets.length - 1) {
                    return label + " : " + value;
                  }
                  else {
                    return [label + " : " + value, "TOTAL[kWh] : " + Math.round(total)];
                  }
                }
              }         
            },
            responsive: true,
            maintainAspectRatio: false,
            scales: {
              xAxes: [{
                stacked: true,
                barPercentage: 0.7
              }],
              yAxes: [
                {
                  stacked: true,
                  position: "left",
                  scaleLabel: {
                    display: true,
                    labelString: 'Kilowatts hora [kWh]'
                  },
                },
                {
                  display: true,
                  stacked: true,
                  position: 'right',
                  id: 'y-axis-ahorro',
                  scaleLabel: {
                    display: true,
                    labelString: 'Ahorro [US$]'
                  },
                  gridLines: {
                    drawOnChartArea: false
                  }
                }
              ]
            }
          },
      
          data: {
            labels: this.barChartLabels,
            datasets: this.metersData,
          }
        });
        this.chartjs = true;
      });
    });
    setTimeout(()=>{
      Swal.close();
    }, 1800)
  }

  getDateWithFormat(view:string, date:string){
    let dateT;
    switch (view){
      case "day": 
        dateT = formatDate(date, 'HH:mm','es-Es','-0600');
        break; 
      case 'week':
        dateT = formatDate(date, 'EEEE dd','es-Es','-0600');
        break;
      case "year":
        dateT = formatDate(date, 'MM/yyyy','es-Es','-0600');
        break;
      default: 
        dateT = formatDate(date, 'dd/MM','es-Es','-0600');
    }
    return dateT;
  }

  // Change visualization type to table view
  changeToTable(){
    let table = document.getElementById("toogleTable");
    let chart = document.getElementById("chart-wrapper");
    this.chartActive = [false, false, false, true];
    chart.style.display = "none";
    table.style.display = "block";
  }

  // Print the table values, according to the generated information
  printTable(){
    printJS(
      { printable: 'measuresTable', type: 'html', 
        //properties: this.displayedColumns.join(","),
        header: '<h3 class="report-header">Datos de la planta </h3>',
        documentTitle: 'DENMARK - Informacion generada',
        style: '.report-header{ color: #075D9D; font-size: 24px; }' }
    );
  }

  // Function for change the chart type without reloading its values
  changeGraphicType(chartType:string){
    let table = document.getElementById("toogleTable");
    let chart = document.getElementById("chart-wrapper");
    chart.style.display = "block";
    table.style.display = "none";
    // Select an interval according to the API permitted param
    let chartT:string;
    switch (chartType)
    { 
      case "bar": 
        this.chartActive = [true, false, false, false];
        if(this.metersData.find(v => (v.type == "radar"))){
          this.metersData.find(v => (v.type != "line")).type = "line";
        }

        break; 
      case "line": 
        this.chartActive = [false, true, false, false];
        if(this.metersData.find(v => (v.type == "radar"))){
          this.metersData.find(v => (v.type != "line")).type = "line";
        }
        break; 
      case "radar":
        this.chartActive = [false, false, true, false];
        this.metersData.find(v => v.type == "line").type = "radar";
        break; 
      default: 
    }  

    this.chart1Type = chartType;

    if (this.chart1 != undefined || this.chart1 == undefined){
      this.chart1.destroy();
    }
    this.chart1 = undefined;
    this.chart1 = new Chart('canvas', {
      type: this.chart1Type,

      options: {
        title: {
          display: true,
        },
        tooltips: {
          mode: 'index',
          callbacks: {
            // Get the total of the energy produced in every point and show it in the hover tooltip
            label: function (tooltipItem, data) { 
              var label = data.datasets[tooltipItem.datasetIndex].label || '';
              var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
              var total = 0;

              for (var i = 0; i < data.datasets.length; i++)
                total += +data.datasets[i].data[tooltipItem.index];

              if (tooltipItem.datasetIndex !== data.datasets.length - 1) {
                return label + " : " + value;
              }
              else {
                return [label + " : " + value, "TOTAL : " + Math.round(total)];
              }
            }
          }         
        },
        responsive: true,
        maintainAspectRatio: false,
        scales: {
          xAxes: [{
            stacked: true,
            barPercentage: 0.7
          }],
          yAxes: [
            {
              stacked: true,
              position: "left",
              scaleLabel: {
                display: true,
                labelString: 'Kilowatts hora [kWh]'
              }
            },
            {
              display: true,
              stacked: false,
              position: 'right',
              id: 'y-axis-ahorro',
              scaleLabel: {
                display: true,
                labelString: 'Ahorro [US$]'
              },
              gridLines: {
                drawOnChartArea: false
              }
            }
          ]
        }
      },
      data: {
        labels: this.barChartLabels,
        datasets: this.metersData,
      }, 
    });
  }

}
