import * as _ from 'underscore';
import Utils, { IUtils } from './Utils';
import { IPageContent } from './Page/Content';
import Emitter, { IEmitter } from './Emitter';

interface ITrackingDataModifiedBy {
  id: number;
  first_name: string;
  last_name: string;
  screen_name: string;
}

export interface ITrackingData {
  content_diff: IPageContent;
  modified_by: ITrackingDataModifiedBy;
  modified_by_timestamp: Date;
}

interface ITrackingHistory {
  [key: string]: ITrackingData[];
}

export interface ITracking extends IEmitter {
  ERROR: string;
  createInstance(): ITracking;
  enabled: boolean;
  addHistory(pageId: number, data: ITrackingData, first?: boolean): void;
  getHistory(pageId: number): any;
  getHistoryForCell(pageId: number, cellRow: number, cellCol: number): any;
  restore(): any;
  reset(): any;
  cancel(): void;
}

export class Tracking extends Emitter implements ITracking {
  public get ERROR(): string {
    return 'error';
  }

  public history: ITrackingHistory = {};
  public enabledPages: number[] = [];
  // public historyFirst: any = {};

  private _enabled: boolean = false;
  private _interval: any;
  private _length: number = 0;
  private _utils: IUtils;

  constructor(private storage: any) {
    super();
    this._utils = new Utils();

    // setInterval(() => {
    //   let length: number = this.totalChanges();
    //   if (this._length !== length) {
    //     this.save();
    //   }
    //   this._length = length;
    // }, 10000);

  }

  public createInstance(): ITracking {
    return new Tracking(this.storage);
  }

  get enabled(): boolean {
    return this._enabled;
  }

  set enabled(value: boolean) {
    if (typeof value !== 'boolean') {
      return;
    }
    this._enabled = value;
    this.cancel();
    if (!value) {
      this.reset();
    } else {
      this.restore();
      // this._interval = setInterval(() => {
      //   let length: number = this.totalChanges();
      //   if (this._length !== length) {
      //     this.save();
      //   }
      //   this._length = length;
      // }, 10000);
    }
  }

  public save(): void {
    try {
      this.storage.user.save('history', JSON.stringify(this.history));
    } catch (e) {
      console.error(e.message);
      this.emit(this.ERROR, e.messsage);
    }
  }

  public enabledPage(pageId: number, enable: boolean): void {
    if (!enable) {
      if (this.history[`page_${pageId}`]) {
        delete this.history[`page_${pageId}`];
      }
      if (this.enabledPages.indexOf(pageId) > -1) {
        this.enabledPages.splice(this.enabledPages.indexOf(pageId), 1);
      }
    } else {
      if (this.enabledPages.indexOf(pageId) < 0) {
        this.enabledPages.push(pageId);
      }
    }
    this.save();
  }

  public addHistory(pageId: number, data: ITrackingData, first: boolean = false): void {
    if (!this.enabled || this.enabledPages.indexOf(pageId) < 0) {
      return;
    }
    if (first && (this.history[`page_${pageId}`] && this.history[`page_${pageId}`].length)) {
      return;
    }
    if (!this.history[`page_${pageId}`]) {
      this.history[`page_${pageId}`] = [];
    }
    this.history[`page_${pageId}`].push(this.compressData(data, first));
    this.save();
  }

  public getHistory(pageId: number): ITrackingData[] {
    if ((!this.enabled && this.enabledPages.indexOf(pageId) < 0) || !this.history[`page_${pageId}`]) {
      return [];
    }
    return this.history[`page_${pageId}`];
  }

  public getHistoryForCell(pageId: number, cellRow: number, cellCol: number): any {
    let history = this.getHistory(pageId);
    if (!history.length) {
      return [];
    }
    let cellHistory: any = [];
    history.forEach((snapshot: any) => {
      snapshot.content_diff.forEach((row: any, rowIndex: number) => {
        if (!row) {
          return;
        }
        row.forEach((col: any, colIndex: number) => {
          if (!col) {
            return;
          }
          if (cellRow === rowIndex && cellCol === colIndex) {
            cellHistory.push({
              cell: JSON.parse(JSON.stringify(col)),
              modified_by: snapshot.modified_by,
              modified_by_timestamp: snapshot.modified_by_timestamp
            });
          }
        });
      });
    });
    return cellHistory;
  }

  public restore(): any {
    this.history = this.storage.user.get('history') || {};
    this._length = this.totalChanges();

    // if (history) {
    //     this.history = JSON.parse(history);
    // }
  }

  public reset(): any {
    this.history = {};
    this.storage.user.remove('history');
  }

  public cancel(): void {
    if (this._interval) {
      clearInterval(this._interval);
      this._interval = null;
    }
  }

  private totalChanges(): number {
    let length: number = 0;
    for (let id in this.history) {
      if (!this.history.hasOwnProperty(id)) {
        continue;
      }
      length += this.history[id].length;
    }
    return length;
  }

  private compressData(data: ITrackingData, first: boolean = false): ITrackingData {
    if (first) {
      data.content_diff = this._utils.clonePageContent(data.content_diff, true);
    }
    return JSON.parse(JSON.stringify(data));
  }
}

export default Tracking;

// export class TrackingWrap {
//     public static $inject: string[] = [];
//     constructor() {
//         return Tracking;
//     }
// }
