import {Component, OnInit} from '@angular/core';
import {ICollection, Resource, Service} from 'ngx-jsonapi';
import {MatDialogConfig} from '@angular/material';
import {DialogComponent} from '../dialog/dialog.component';
import {Dialog} from '../dialog/dialog';
import {EditComponent} from '../edit/edit.component';
import {IParamsResource} from 'ngx-jsonapi/interfaces';
import {Headers, Http} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import {CookieService} from 'ngx-cookie-service';
import {environment} from '../../../../environments/environment';

@Component({
  selector: 'app-list',
  template: '',
})
/**
 * @param columns آرایه ای  هست که هر عضوش یه آبجکت هست که شامل موارد زیر
 * prop : که نماینده یک ستون است که نام آن عینا باید با نام ی که از سرور گرفته می شود یکی باشد. اگر ریلیشن بود نیز باید عین نام ریلیشن باشد.
 * relationshipPropToShow : بصورت پیشفرض name است اما اگر نبود اون فیلد از ریلیشن شیپ نشون داده میشه
 * isRelationship تعیین میکند که این ستون یک ریلیشن شیپ است
 * rows متغیری از ارایه برای تعریف سطر
 * columns متغیری از ارایه برای تعریف ستون
 * sortprop مرتب کردن بر اساس id
 * sortdir مرتب کردن به صورت صعودی نزولی
 * count مقدار total در تیبل
 * limit تعداد سطر ها در هر صفحه
 * offset برای pagination و جابجا شدن بین صفخات
 * is_loading قرار داد های jsonapi برای load کردن یوزر ها تا وقتی کامل نشده باشه true میمونه . وقتی false شد و ریسورس از سرور نبود ارایه از دیتا توی رو در filteredOptions ذخیره کنه
 * filteredOptions ریسپانس های سرور رو اینخا ذخیره میکنه
 *filters یه متغیری برای فیلتر ها
 */
export class ListComponent implements OnInit {
  rows = [];
  columns = [];
  allColumns = [];
  sortProp = 'id';
  sortDir = 'asc';
  count = 0;
  limit = 10;
  offset = 0;
  is_loading = false;
  filters = {};
  filteredOptions = [];
  lists;
  appUrl: any;
  includes;

  /**
   *
   * @param {Service} listService baray estefade az resource
   * @param {Dialog} dialog  baray baz kardan dialog
   * @param {EditComponent} editComponent ye component pedar baray ers barie dialog
   */
  constructor(public listService: Service,
              public dialog: Dialog,
              public editComponent: EditComponent,
              public http: Http,
  ) {
    this.appUrl = environment.app_url;
  }

  ngOnInit() {
    // this.allColumns = this.columns;
    this.allColumns = this.columns.filter(c => {
      return c.prop !== 'id';
    });
    this.fetchList('null');
    // set columns from server
    let cols = JSON.parse(localStorage.getItem('columns'));
    if (cols[window.location.pathname]) {
      cols = cols[window.location.pathname].toString();
    } else {
      cols = '';
    }
    cols = cols.split(',');
    // column haei ro bede ke too cols array bashe
    if (cols[0] != '') {
      this.columns = this.columns.filter(c => {
        return cols.indexOf(c.prop) > -1;
      });
    }
  }

  /***
   *
   * @param event ye roydad baray sort filter limit....
   */
  fetchList(event) {
    this.is_loading = true;
    if (event) {
      if (event.hasOwnProperty('sorts')) {
        this.sortProp = event.sorts[0].prop;
        this.sortDir = event.sorts[0].dir;
        this.setDefaultNumberts();
      }
      if (event.hasOwnProperty('count')) {
        this.count = event.count;
      }
      if (event.hasOwnProperty('limit')) {
        this.limit = event.limit;
      }
      if (event.hasOwnProperty('offset')) {
        this.offset = event.offset;
      }
      if (event == 'filter') {
        this.setDefaultNumberts();
      }
      if (event == 'refresh') {
        this.setDefaultSorts();
        this.setDefaultFilters();
      }
    }
    this.includes = [];
    let that = this;
    for (let key in this.columns) {
      if (this.columns[key].mustIncluded) {
        that.includes.push(this.columns[key].prop);
      }
    }
    this.listService.all(
      {
        page: {number: this.offset + 1, size: this.limit},
        sort: {prop: this.sortProp, dir: this.sortDir},
        remotefilter: this.repairFilterObj(this.filters),
        include: that.includes
      }
    ).subscribe(lists => {
        if (lists.$source != 'server' || lists.$is_loading) {
          return;
        }
        this.rows = [];
      let listsArray = lists.$toArray;
        let page: any = lists.page.number;
        this.count = page.total;
        this.limit = page['per-page'];
        this.offset = page['current-page'] - 1;
        for (let list_key in listsArray) {
          let row = [];
          row['id'] = listsArray[list_key].id;
          for (let key in this.columns) {
            let prop = this.columns[key].prop;
            if (prop == 'id') {
            } else if (this.columns[key].replaceFunc) {
              row[prop] = this.columns[key].replaceFunc(listsArray[list_key].attributes[prop]);
            } else {
              if (this.columns[key].isRelationship) {
                const relationData = listsArray[list_key].relationships[prop]['data'];
                if (!relationData.hasOwnProperty('page') && relationData.hasOwnProperty('attributes')) { // has one
                  if (this.columns[key]['relationshipPropToShow']) {
                    row[prop] = listsArray[list_key].relationships[prop]['data']['attributes'][this.columns[key]['relationshipPropToShow']];

                  } else // pishfarz name gharar dade mishavad
                  {
                    row[prop] = listsArray[list_key].relationships[prop]['data']['attributes']['name'];
                  }
                } else if (relationData.hasOwnProperty('page')) { // has many
                  // aval bayad relationData be Icollection cast shavad
                  const relationsData = (relationData as ICollection<Resource>).$toArray;

                  const names: string[] = [];
                  for (const key2 in relationsData) {
                    if (relationsData[key2].hasOwnProperty('attributes')) {
                      if (this.columns[key]['relationshipPropToShow']) {
                        names.push(relationsData[key2]['attributes'][this.columns[key]['relationshipPropToShow']]);
                      } else
                      // pishfarz name gharar dade mishavad
                      {
                        names.push(relationsData[key2]['attributes']['name']);
                      }
                    }
                  }
                  row[prop] = (names.join(',')).substr(0, 10) + '...';
                } else {
                  row[prop] = '';
                }
              } else {
                row[prop] = listsArray[list_key].attributes[prop];
              }

            }
          }
          let exists = false;

          for (let key in this.rows) {
            if (this.rows[key]['id'] == row['id']) {
              exists = true;
            }
          }
          if (!exists) {
            this.rows.push(row);
          }

        }
        this.lists = lists;

      }, error => {
        console.log(error);
      }, () => {
        this.is_loading = false;
      }
    );
  }

  /**
   * برای جابجایی بین صفحات موقع load شدن صفر رو برمیگردونه
   */
  setDefaultNumberts() {
    this.offset = 0;
  }

  /**
   * @ setDefaultSorts()  برای وقتی داده ها رو بخواهیم مرتب کنیم
   * @ setDefaultFilters() برای وقتی که دادهها را فیلتر و رفرش میکنیم filters خالی میکند و داده ها رو بر میگرداند
   */
  setDefaultSorts() {
    this.offset = 0;
    this.sortProp = 'id';
    this.sortDir = 'asc';
  }

  setDefaultFilters() {
    this.filters = {};

  }

  /****
   *
   * @param filters برای تبدیل کردن فیلتر ها به آرایه و قرار دادن کاما بینشون
   * @returns {any[]}
   */
  repairFilterObj(filters) {
    let ret = [];
    for (var key in filters) {
      if (Array.isArray(filters[key])) {
        ret[key] = filters[key].join(',');
      } else {
        ret[key] = filters[key];
      }
    }

    return ret;
  }

  /***
   *
   * @param id in tabe bar asas id hazf mikone
   */
  remove(id) {
    const dialogConfig = new MatDialogConfig();
    dialogConfig.disableClose = true;
    dialogConfig.autoFocus = true;
    dialogConfig.data = {
      message: 'آیا مطمئن هستید؟',
      type: 'yesno'
    };

    const dialogRef = this.dialog.open(DialogComponent, dialogConfig);
    dialogRef.afterClosed().subscribe(
      result => {
        if (result) {
          this.listService.delete(id).subscribe(ok => {
            this.fetchList(null);
          }, error => {
            var p = error.errors;
            for (const key in p) {
              const err = p[key];
              alert(err.title + ':' + err.detail);
            }
          });
        }
      }
    );

  }

  edit(id?, params?: IParamsResource | null) {

    if (!id) {
      const resource = this.listService.new();
      // let requiredPermission = this.listService.requestType + '.create';
      // if(hasAccess(requiredPermission))
      // {
      const dialogRef = this.dialog.openWithData(this.editComponent, resource);
      dialogRef.afterClosed().subscribe(
        (ok) => {
          this.fetchList(null);
        }
      );
      // }
      // else
      // {
      // this.dialog.openForAlert('access denied');
      // }

    } else {
      //   {
      // let requiredPermission = this.listService.requestType + '.update';
      // if (hasAccess(requiredPermission)) {
      this.listService.get(id, params)
        .subscribe(
          resource => {
            if (resource.is_loading) {
              return;
            }
            const dialogRef = this.dialog.openWithData(this.editComponent, resource);
            dialogRef.afterClosed().subscribe(
              (ok) => {
                this.fetchList(null);
              }
            );
          }
        );
      // }
    }
  }


  /**
   *
   * @param {Service} کدوم ریسورس سرچ شود؟
   * @param {string} value دنبال چی بگردیم
   * @param {string} prop baray set kardan soton hay html ba ts
   * bar asas prop filter mikone
   * @param {string} key kodom filde ro fileter.kone pishfarz name hast
   * @private
   */
  protected _filter(service: Service, value: string, prop: string, key: string = 'name', otherFilters: object = {}) {
    let remoteFilter = otherFilters;
    remoteFilter[key] = value;
    service.all({
      remotefilter: remoteFilter,
      page: {number: 1, size: 5}
    }).subscribe(data => {
      if (data.$source != 'server' || data.$is_loading) {
        return;
      }
      this.filteredOptions[prop] = data.$toArray;

    });
  }

  /***
   * این تابغ برای فیلتر MAt option هست که  عمل فیلتر و fetchlist رو انجام میده
   * @param key بر اساس چی فیلتر کنه
   * @param value مقداری که قراره فیلتر کنیم
   */
  protected setFiltersVarAndRefresh(key, value) {
    this.filters[key] = value;
    this.fetchList('filter');
  }

  toggle(col): Observable<boolean> {
    const isChecked = this.isChecked(col);
    if (isChecked) {
      if (this.columns.length < 2 || col.prop == 'id') {
        return;
      }
      this.columns = this.columns.filter(c => {
        return c.prop !== col.prop;
      });
    } else {
      this.columns = [col , ...this.columns];
    }
    // sort ba asase all columns
    this.columns = this.columns.filter(c => {
      return this.columns.find(c2 => {
        return c.prop === c2.prop;
      });
    });
    let cols = [];
    for (let key in this.columns) {
      cols.push(this.columns[key]['prop']);
    }
    this.setColumns(cols).subscribe(result => {
      this.fetchList('null');
    }, error1 => {
    });
  }

  isChecked(col) {
    return this.columns.find(c => {
      return c.prop === col.prop;
    });
  }

  setColumns(cols): Observable<boolean> {
    const headers = new Headers();
    const cookieService: CookieService = new CookieService('');
    headers.append('Content-Type', 'application/x-www-form-urlencoded');
    headers.append('Authorization', 'Bearer ' + localStorage.getItem('token'));
    return this.http.post('https:' + environment.app_url + 'set_columns',
      'route=' + window.location.pathname +
      '&props=' + cols.join(',')
      ,
      {headers: headers})
      .map(res => {
        localStorage.setItem('columns', res.text());
        return true;
      });
  }
}
