import moment from 'moment-timezone';
import Promise from 'bluebird';
import { IAuthService } from './Auth';
import { IApiService } from './Api';
import merge from 'deepmerge';

let api: IApiService, auth: IAuthService;

export class UsageWrap {
  constructor(ippApi: IApiService, ippAuth: IAuthService) {
    api = ippApi;
    auth = ippAuth;
  }
}

export interface IUsage {
  load(folderId?: number): any;
}

export default class Usage implements IUsage {
  public static $inject: string[] = ['$timeout', '$interval', '$q', 'ippApiService', 'ippAuthService'];

  // org users
  // org folders

  public folders: any[] = [];
  public filteredFolders: any[] = [];
  public folderFilter: any = {
    name: ''
  };

  public pages: any[] = [];
  public filteredPages: any[] = [];
  public pageFilter: any = {
    name: ''
  };

  public users: any[] = [];
  public filteredUsers: any[] = [];
  public userFilter: any = {
    emails: '',
    screen_name: '',
    full_name: ''
  };

  public stats: any = {};
  public orgStats: any = {};

  public indicator: string = 'usage';
  public type: string = 'PUSH';
  public output: string = 'percentage';

  public threshold: any = {
    percentage: {
      from: 25,
      to: 75
    },
    count: {
      from: 100,
      to: 1000
    },
    usage: {
      from: 1,
      to: 3
    }
  };

  public sortBy: any = {
    folders: {
      users: 'usage',
      folders: 'usage'
    },
    pages: {
      users: 'usage',
      folders: 'usage'
    }
  };

  public date: any = {
    from: moment()
      .subtract(30, 'days')
      .format('YYYYMMDD'),
    to: moment().format('YYYYMMDD')
  };

  public datePicker: any = {
    date: {
      startDate: moment().subtract(30, 'days'),
      endDate: moment()
    },
    options: {
      locale: {
        cancelLabel: 'Cancel'
      },
      drops: 'down',
      opens: 'left',
      eventHandlers: {
        'apply.daterangepicker': undefined
      },
      ranges: {
        'Last 30 Days': [moment().subtract(30, 'days'), moment()],
        'Last 7 Days': [moment().subtract(7, 'days'), moment()],
        'Previous day': [moment(), moment().add(1, 'days')]
      }
    }
  };

  public statTotals: any = {
    PULL: {
      count: 0,
      usage: 0
    },
    PUSH: {
      count: 0,
      usage: 0
    }
  };
  public statTotalsByFolder: any = {};

  private folderId: number = 0;
  private statDefault: any = {
    PULL: {
      count: 0,
      usage: 0
    },
    PUSH: {
      count: 0,
      usage: 0
    }
  };

  private q: any;

  constructor(private api: IApiService, private auth: IAuthService) {}

  public load(folderId?: number): any {
    this.folderId = folderId === undefined ? 0 : folderId;
    this.folders = [];
    this.pages = [];
    this.orgStats = {};
    this.stats = {};
    this.statTotals = merge({}, this.statDefault);
    this.statTotalsByFolder = {};
    // this.q = this.$q.defer();
    let p: Promise<any> = new Promise((resolve, reject) => {
      this.emptyAsync()
        .then(() => {
          if (folderId) {
            return this.api.getDomainPages(folderId);
          } else {
            return this.api.getOrganizationDomains({
              organizationId: this.auth.user.organization_id
            });
          }
        })
        .then((response: any) => {
          if (folderId) {
            this.pages = response.data.pages || [];
            return this.api.getDomainPageAccess({
              domainId: folderId
            });
          } else {
            this.folders = response.data.results || [];
            return this.api.getOrganizationUsers({
              organizationId: this.auth.user.organization_id
            });
          }
        })
        .then((response: any) => {
          if (folderId) {
            this.users = [];
            let users: any = response.data.user_domain_access;
            users.forEach((user: any) => {
              this.users.push(user.user);
            });
            return this.api.getDomainUsage({
              domainId: folderId,
              fromDate: this.date.from,
              toDate: this.date.to
            });
          } else {
            this.users = response.data.results || [];
            return this.api.getOrganizationUsage({ fromDate: this.date.from, toDate: this.date.to });
          }
        })
        .then((response: any) => {
          if (folderId) {
            response.data.results.forEach((result: any) => {
              if (!result.user_id) {
                return;
              }
              // check if user exits
              let count: boolean = false;
              this.users.forEach(user => {
                if (user.id !== result.user_id) {
                  return;
                }
                count = true;
              });
              if (!count) {
                return;
              }

              // overall
              this.statTotals[result.request_method].count += result.total_requests;
              this.statTotals[result.request_method].usage += result.total_requests_size;
              // by folder
              if (!this.statTotalsByFolder[result.page_id]) {
                this.statTotalsByFolder[result.page_id] = merge({}, this.statDefault);
              }
              this.statTotalsByFolder[result.page_id][result.request_method].count += result.total_requests;
              this.statTotalsByFolder[result.page_id][result.request_method].usage += result.total_requests_size;

              if (!this.stats[result.user_id]) {
                this.stats[result.user_id] = {};
              }
              if (!this.stats[result.user_id][result.page_id]) {
                this.stats[result.user_id][result.page_id] = merge({}, this.statDefault);
              }
              this.stats[result.user_id][result.page_id][result.request_method] = {
                count: result.total_requests,
                usage: result.total_requests_size
              };
            });
          } else {
            response.data.results.forEach((result: any) => {
              // overall
              this.statTotals[result.request_method].count += result.total_requests;
              this.statTotals[result.request_method].usage += result.total_requests_size;
              // by folder
              if (!this.statTotalsByFolder[result.domain_id]) {
                this.statTotalsByFolder[result.domain_id] = merge({}, this.statDefault);
              }
              this.statTotalsByFolder[result.domain_id][result.request_method].count += result.total_requests;
              this.statTotalsByFolder[result.domain_id][result.request_method].usage += result.total_requests_size;

              if (!result.user_id) {
                return;
              }
              if (!this.orgStats[result.user_id]) {
                this.orgStats[result.user_id] = {};
              }
              if (!this.orgStats[result.user_id][result.domain_id]) {
                this.orgStats[result.user_id][result.domain_id] = merge({}, this.statDefault);
              }
              this.orgStats[result.user_id][result.domain_id][result.request_method] = {
                count: result.total_requests,
                usage: result.total_requests_size
              };
            });
          }
          this.users.forEach(user => {
            user.stats = merge({}, this.statDefault);
            let pagesFolders: any = folderId ? this.pages : this.folders;
            let statsData: any = folderId ? this.stats : this.orgStats;
            pagesFolders.forEach((n: any) => {
              if (!statsData[user.id] || !statsData[user.id][n.id]) {
                if (!statsData[user.id]) {
                  statsData[user.id] = {};
                }
                statsData[user.id][n.id] = merge({}, this.statDefault);
                return;
              }
              ['PULL', 'PUSH'].forEach(method => {
                user.stats[method].count += statsData[user.id][n.id][method]
                  ? statsData[user.id][n.id][method].count
                  : 0;
                user.stats[method].usage += statsData[user.id][n.id][method]
                  ? statsData[user.id][n.id][method].usage
                  : 0;
              });
            });
          });
          console.log('users', this.users);
        })
        .catch(reject)
        .finally(() => {
          if (folderId) {
            this.queryPages();
          } else {
            this.queryFolders();
          }
          console.log('finally');
          console.log(this.statTotals);
          console.log(this.statTotalsByFolder);
          this.queryUsers();
          resolve({
            users: this.filteredUsers,
            pages: this.filteredPages,
            folders: this.filteredFolders,
            stats: this.stats,
            statTotals: this.statTotals,
            statTotalsByFolder: this.statTotalsByFolder,
            orgStats: this.orgStats
          });
        });
    });
    return p;
    // return this.q.promise;
  }

  public setSortBy(which: string, type: string, value: string | number): void {
    this.sortBy[which][type] = value;
    this.queryUsers();
    this.queryFolders();
    this.queryPages();
  }

  public queryFolders(): void {
    let folders: any[] = [];
    let folderNames: string[] = this.folderFilter.name.split(',');
    this.folders.forEach(f => {
      // f = this.updateFolderStatus(f);
      if (!this.folderFilter.name) {
        folders.push(f);
        return;
      }
      folderNames.forEach(name => {
        name = name.trim();
        if (!name) {
          return;
        }
        if (f.name.toLowerCase().indexOf(name.toLowerCase()) > -1 && folders.indexOf(f) < 0) {
          folders.push(f);
        }
      });
    });
    folders.sort((a, b) => {
      // if (this.folderId) {
      if (
        (this.folderId && this.sortBy.pages.folders === 'usage') ||
        (!this.folderId && this.sortBy.folders.folders === 'usage')
      ) {
        let aStat: number = this.statTotalsByFolder[a.id]
          ? this.statTotalsByFolder[a.id][this.type][this.indicator]
          : 0;
        let bStat: number = this.statTotalsByFolder[b.id]
          ? this.statTotalsByFolder[b.id][this.type][this.indicator]
          : 0;
        if (aStat < bStat) {
          return 1;
        }
        if (aStat > bStat) {
          return -1;
        }
        return 0;
      }
      // }

      if (a.name.toLowerCase() > b.name.toLowerCase()) {
        return 1;
      }
      if (a.name.toLowerCase() < b.name.toLowerCase()) {
        return -1;
      }
      return 0;
    });
    this.filteredFolders = folders;
  }

  public queryPages(): void {
    let pages: any[] = [];
    let pageNames: string[] = this.pageFilter.name.split(',');
    this.pages.forEach(f => {
      // f = this.updateFolderStatus(f);
      if (!this.pageFilter.name) {
        pages.push(f);
        return;
      }
      pageNames.forEach(name => {
        name = name.trim();
        if (!name) {
          return;
        }
        if (f.name.toLowerCase().indexOf(name.toLowerCase()) > -1 && pages.indexOf(f) < 0) {
          pages.push(f);
        }
      });
    });
    pages.sort((a, b) => {
      if (this.folderId) {
        if (this.sortBy.pages.folders === 'usage') {
          let aStat: number = this.statTotalsByFolder[a.id]
            ? this.statTotalsByFolder[a.id][this.type][this.indicator]
            : 0;
          let bStat: number = this.statTotalsByFolder[b.id]
            ? this.statTotalsByFolder[b.id][this.type][this.indicator]
            : 0;
          if (aStat < bStat) {
            return 1;
          }
          if (aStat > bStat) {
            return -1;
          }
          return 0;
        }
      }

      if (a.name.toLowerCase() > b.name.toLowerCase()) {
        return 1;
      }
      if (a.name.toLowerCase() < b.name.toLowerCase()) {
        return -1;
      }

      return 0;
    });
    this.filteredPages = pages;
  }

  public queryUsers(): void {
    let users: any[] = [];
    this.users.forEach(f => {
      // if (!this.filter) {
      //     users.push(f);
      //     return;
      // }
      let add: boolean = true;
      if (this.userFilter.emails) {
        let emails: any[] = this.userFilter.emails.split(',');
        add = false;
        emails.forEach(email => {
          if (!email.trim()) {
            return;
          }
          if (f.email.indexOf(email.trim()) > -1) {
            add = true;
          }
        });
      }
      if (this.userFilter.screen_name && f.screen_name.indexOf(this.userFilter.screen_name) === -1) {
        add = false;
      }
      if (this.userFilter.full_name && f.full_name.indexOf(this.userFilter.full_name) === -1) {
        add = false;
      }
      if (add) {
        users.push(f);
      }
    });
    users.sort((a, b) => {
      if (this.folderId) {
        if (this.sortBy.pages.users === 'usage') {
          if (a.stats[this.type][this.indicator] < b.stats[this.type][this.indicator]) {
            return 1;
          }
          if (a.stats[this.type][this.indicator] > b.stats[this.type][this.indicator]) {
            return -1;
          }
          return 0;
        }
      } else {
        if (this.sortBy.folders.users === 'usage') {
          if (a.stats[this.type][this.indicator] < b.stats[this.type][this.indicator]) {
            return 1;
          }
          if (a.stats[this.type][this.indicator] > b.stats[this.type][this.indicator]) {
            return -1;
          }
          return 0;
        }
      }
      if (a.email.toLowerCase() > b.email.toLowerCase()) {
        return 1;
      }
      if (a.email.toLowerCase() < b.email.toLowerCase()) {
        return -1;
      }
      return 0;
    });
    this.filteredUsers = users;
  }

  public convertNumber(indicator: string, value: any): string {
    if (!value) {
      return '0';
    }
    if (indicator === 'usage') {
      value = parseFloat((value / 1024 / 1024).toFixed(1)).toLocaleString();
      if (!parseFloat(value)) {
        value = '0.1';
      }
    }
    value = value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return value || '0';
  }

  public pageFolderPercentage(type: string, indicator: string, value: number): string {
    if (!value) {
      return '0';
    }
    return ((value / this.statTotals[type][indicator]) * 100).toFixed(1);
  }

  public cellClass(stat: number, folderId?: number): string {
    if (!stat) {
      return 'NA';
    }

    let from: any = this.output === 'percentage' ? this.threshold.percentage.from : this.threshold[this.indicator].from;
    let to: any = this.output === 'percentage' ? this.threshold.percentage.to : this.threshold[this.indicator].to;
    if (this.indicator === 'usage' && this.output !== 'percentage') {
      stat = stat / 1024 / 1024;
    } else if (this.output === 'percentage' && folderId) {
      stat = (stat / this.statTotalsByFolder[folderId][this.type][this.indicator]) * 100;
    }
    if (stat < from) {
      return '';
    }
    if (stat >= from && stat <= to) {
      return 'RW';
    }
    if (stat > to) {
      return 'NO';
    }
    return '';
  }

  public cellValue(pushes: any, folderId?: number): string {
    if (!pushes) {
      return '';
    }
    let value: any = pushes[this.indicator];
    if (!value) {
      return '';
    }
    if (this.output === 'percentage' && folderId) {
      if (!this.statTotalsByFolder[folderId]) {
        value = '#';
      } else {
        value = ((value / this.statTotalsByFolder[folderId][this.type][this.indicator]) * 100).toFixed(1);
      }
    } else if (this.indicator === 'usage') {
      value = parseFloat((value / 1024 / 1024).toFixed(1));
      if (!parseFloat(value)) {
        value = 0.1;
      }
    }
    return value;
  }

  private emptyAsync(): any {
    let p: Promise<any> = new Promise(resolve => {
      resolve();
    });
    return p;
  }
}
