/*
 * Copyright (C) 2019 Robert Bosch GmbH Copyright (C) 2019 Robert Bosch Manufacturing Solutions GmbH, Germany. All rights reserved.
 */

import { Injectable } from '@angular/core';
import { PinboardConfig, Widget } from '@bci-web-core/pinboard';
import { from, Observable, of } from 'rxjs';
import { concatMap, map } from 'rxjs/operators';

const STORAGE_KEY = 'BCI_DASHBOARD_USER_CONFIG';
const DASHBOARD_ID = 'DASHBOARD_';

@Injectable({
  providedIn: 'root',
})
export class DashboardService {
  private pinboardConfig: PinboardConfig;
  private allDashboards: any[] = [];

  loadUserConfiguration(dashboardId: string): Observable<PinboardConfig> {
    return this.readDashboard(dashboardId).pipe(
      map((cfg) => {
        this.pinboardConfig = { ...cfg };
        console.log('WIDGETS', this.pinboardConfig.settings);
        return cfg;
      })
    );
  }

  updateWidget(widget: Widget): Observable<PinboardConfig> {
    const index = this.pinboardConfig.settings.findIndex((gridWidget) => gridWidget.id === widget.id);
    if (index > -1) {
      console.log('UPDATE WIDGET', widget);
      this.pinboardConfig.settings.splice(index, 1, widget);
      return this.saveDashboard(this.pinboardConfig);
    }
  }

  /**
   * Saves any changes to the dashboard
   */
  saveDashboard(config: PinboardConfig): Observable<PinboardConfig> {
    const widgets = config.settings.slice().map((gridWidget: Widget) => {
      return {
        id: gridWidget.id,
        title: gridWidget.title,
        sizeArray: gridWidget.sizeArray,
        isLinkedToFilter: gridWidget.isLinkedToFilter,
        showWidgetTitle: gridWidget.showWidgetTitle,
        gridsterItem: gridWidget.gridsterItem,
        userSettingsValues: {
          ...gridWidget.getUserSettingsObject(),
        },
        widgetDefinition: {
          id: gridWidget.widgetDefinition.id,
        },
      };
    })

    const dashboards = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
    const dashboard = dashboards.find(dashboard => dashboard.id === config.id);
    dashboard.settings = widgets;
    localStorage.setItem(STORAGE_KEY, JSON.stringify(dashboards));
    return of(this.pinboardConfig);
  }

  /**
   * Created a new dashboard
   */
  createDashboard(dashboardName: string, priority?: number): Observable<PinboardConfig> {
    const newDashboard = {
      id: this.generateDashboardId(),
      label: dashboardName || 'Dashboard',
      settings: [],
      priority: priority || 0,
    };
    this.allDashboards.push(newDashboard);
    localStorage.setItem(STORAGE_KEY, JSON.stringify(this.allDashboards));
    return of(newDashboard);
  }

  /**
   * Gets all the tabs for a particular tenant
   */
  getAllDashboardHeaders(): Observable<PinboardConfig[]> {
    this.allDashboards = JSON.parse(localStorage.getItem(STORAGE_KEY)) || [];
    if (this.allDashboards && this.allDashboards.length > 0) {
      return of(this.sortDashboards(this.allDashboards));
    } else {
      return of(null);
    }
  }

  /**
   * Updates dashboard headers - labels and priority
   */
  updateDashboardHeaders(dashboards: PinboardConfig[]): Observable<PinboardConfig[]> {
    dashboards.forEach((item) => {
      const index = this.allDashboards.findIndex((dashboard) => dashboard.id === item.id);
      if (index > -1) {
        this.allDashboards[index].label = item.label;
        this.allDashboards[index].priority = item.priority;
      }
    });
    localStorage.setItem(STORAGE_KEY, JSON.stringify(this.allDashboards));
    return of(this.allDashboards);
  }

  /**
   * Deletes multiple dashboards
   */
  deleteDashboards(dashboardIds: string[]): Observable<any> {
    dashboardIds.forEach((id) => {
      const matchIndex = this.allDashboards.findIndex((item) => item.id === id);
      if (matchIndex > -1) {
        this.allDashboards.splice(matchIndex, 1);
      }
    });
    localStorage.setItem(STORAGE_KEY, JSON.stringify(this.allDashboards));
    return of(true);
  }

  /**
   * Called when the user saves dashboard user settings
   */
  updateAllDashboards(
    created: PinboardConfig[],
    updated: PinboardConfig[],
    deleted: string[]
  ): Observable<PinboardConfig[]> {
    const createRequest =
      created.length > 0
        ? from(created).pipe(concatMap((item) => this.createDashboard(item.label, item.priority)))
        : of(null);

    const updateRequest = updated.length > 0 ? this.updateDashboardHeaders(updated) : of(null);

    const deleteRequest = deleted.length > 0 ? this.deleteDashboards(deleted) : of(null);

    const getAllRequest = this.getAllDashboardHeaders();

    return createRequest.pipe(
      concatMap(() => updateRequest),
      concatMap(() => deleteRequest),
      concatMap(() => getAllRequest.pipe(map((res) => this.sortDashboards(res))))
    );
  }

  /**
   * Sorts dashboard list based on priority
   */
  sortDashboards(dashboards: PinboardConfig[]): PinboardConfig[] {
    dashboards.sort((a, b) => {
      return a.priority - b.priority;
    });
    return dashboards;
  }

  /**
   * Reads dashboard details based on its id.
   */
  private readDashboard(dashboardId: string): Observable<PinboardConfig> {
    const dashboard = JSON.parse(localStorage.getItem(STORAGE_KEY)).find((item) => item.id === dashboardId);    
    dashboard.settings = typeof dashboard.settings === 'string' ? JSON.parse(dashboard.settings) : dashboard.settings;
    dashboard.settings.forEach((gridWidget) => {
      gridWidget.getUserSettingsObject = () => gridWidget.userSettingsValues; // TEMP
      gridWidget.getUserSettingValue = (id) => (gridWidget.userSettingsValues || {})[id]; // TEMP
      return gridWidget;
    });
    return of(dashboard);
  }

  private generateDashboardId() {
    return DASHBOARD_ID + Math.round(Math.random() * 1000);
  }
}
