import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core';
import {Location} from '@angular/common';
import {ActivatedRoute, Router} from '@angular/router';
import {Subject, Subscriber} from 'rxjs';
import {debounceTime, distinctUntilChanged} from 'rxjs/operators';
import {ClaimsService} from '../service/claims.service';
import {User} from '../../../login/utils/helper.class';
import {EnvProperties} from '../../../utils/properties/env-properties';
import {SEOService} from '../../../sharedComponents/SEO/SEO.service';
import {IndexInfoService} from '../../../utils/indexInfo.service';
import {ClaimDBRecord} from '../claimHelper.class';
import {Dates} from '../../../utils/string-utils.class';
import {HelperService} from '../../../utils/helper/helper.service';
import {Meta, Title} from '@angular/platform-browser';
import {PiwikService} from '../../../utils/piwik/piwik.service';
import {properties} from '../../../../../environments/environment';
import {FormBuilder, FormGroup} from '@angular/forms';
import {Option} from '../../../sharedComponents/input/input.component';
import {OpenaireEntities} from "../../../utils/properties/searchFields";
import {HelperFunctions} from "../../../utils/HelperFunctions.class";
import {NotificationHandler} from "../../../utils/notification-handler";
import {DropdownFilterComponent} from "../../../utils/dropdown-filter/dropdown-filter.component";

@Component({
  selector: 'displayClaims',
  templateUrl: 'displayClaims.component.html',
  styleUrls: ['displayClaims.component.less']
})
export class DisplayClaimsComponent implements OnInit, OnDestroy {
  @Input() pageTitle: string = "";
  properties: EnvProperties;
  public searchTermStream = new Subject<string>();
  subscriptions: any = [];
  public subResults: any;
  //string because comes as input from component directive
  @Input() enableDelete: boolean = false;
  @Input() showUserEmail: boolean = true;
  @Input() myClaims: boolean = false;
  @Input() isAdmin: boolean = false;
  page: number = 1;
  size: number = 50;
  keyword: string; // the keyword string to give to the request as parameter
  types = ["All", "Project", "Context", "Result", "User"];
  loading: boolean = false;
  @Input() fetchBy: string;
  @Input() fetchId: string;
  @Input() user: User;
  resultsNum: number = 0;
  claims: ClaimDBRecord[];
  @Input() externalPortalUrl: string = null;
  @Input() claimsInfoURL: string;// ="https://www.openaire.eu/linking";
  lastIndexDate = null;
  public filterForm: FormGroup;
  public entities: string[] = [];
  selected = [];
  
  allOptions: Option[] = [
    {label: OpenaireEntities.PUBLICATIONS, value: "publication"},
    {label: OpenaireEntities.DATASETS, value: "dataset"},
    {label: OpenaireEntities.SOFTWARE, value: "software"},
    {label: OpenaireEntities.OTHER, value: "other"},
    {label: OpenaireEntities.PROJECTS, value: "project"},
    {label: OpenaireEntities.COMMUNITIES, value: "context"}];
  
  sortOptions: Option[] = [
    {label: "Date (recent) ", value: {sort: "date", descending: true}},
    {label: "Date (oldest) ", value: {sort: "date", descending: false}},
    {label: "Title (desc) ", value: {sort: "target", descending: true}},
    {label: "Title (asc) ", value: {sort: "target", descending: false}},
  ];
  entityTypes: string[] = [];
  index: number;
  params;
  @ViewChild("deleteModal") deleteModal;
  
  claimsDeleted: number = 0;
  @Input() communityId: string = null;
  
  url = null;
  public pageContents = null;
  
  /* Sticky actions */
  @Input()
  public actions: boolean = false;
  public offset: number;
  
  constructor(private _claimService: ClaimsService, private route: ActivatedRoute, private _router: Router, private location: Location,
              private _meta: Meta, private _title: Title, private _piwikService: PiwikService,
              private seoService: SEOService, private indexInfoService: IndexInfoService, private helper: HelperService, private _fb: FormBuilder) {
  }
  
  ngOnInit() {
    if (typeof document !== "undefined" && this.actions) {
      this.offset = Number.parseInt(getComputedStyle(document.documentElement).getPropertyValue('--header-height'));
    }
    this.entities = [];
    this.filterForm = this._fb.group({
      keyword: [''],
      entities: this._fb.control(this.entities),
      sort: this._fb.control(this.sortOptions[0].value)
    });
    
    this.properties = properties;
    this.url = properties.domain + properties.baseLink + this._router.url;
    if (!this.myClaims) {
      this.sortOptions.push({label: "User (desc) ", value: {sort: "user", descending: true}});
      this.sortOptions.push({label: "User (asc) ", value: {sort: "user", descending: false}})
    }
    var description = "Openaire, linking, claim, publication, research data, software, other research product, project, community";
    this.updateTitle(this.pageTitle);
    this.updateDescription(description);
    this.updateUrl(this.url);
    this.subscriptions.push(this._piwikService.trackView(this.properties, this.pageTitle).subscribe());

    if(properties.adminToolsPortalType !== "explore") {
      this.subscriptions.push(this.helper.getPageHelpContents(this.properties, this.communityId, this._router.url).subscribe(contents => {
        this.pageContents = contents;
      }));
    }
    this.subscriptions.push(this.indexInfoService.getLastIndexDate(this.properties).subscribe(res => {
      this.lastIndexDate = res;
    }));
    this.subscriptions.push(this.route.queryParams.subscribe(params => {
      this.seoService.createLinkForCanonicalURL(this.url, false);
      
      if (this.myClaims) {
        this.fetchBy = "User";
        this.fetchId = this.user.email;
      } else {
        this.fetchBy = (this.fetchBy) ? this.fetchBy : params['fetchBy'];
        this.fetchBy = (this.types.indexOf(this.fetchBy) != -1) ? this.fetchBy : 'All';
        this.fetchId = (this.fetchId) ? this.fetchId : params['fetchId'];
        this.fetchId = this.fetchId ? this.fetchId : '';
      }
      let page = (params['page'] === undefined) ? 1 : +params['page'];
      this.keyword = (params['keyword'] ? params['keyword'] : "");
      this.filterForm.get('keyword').setValue(this.keyword);
      this.page = (page <= 0) ? 1 : page;
      this.entityTypes = [];//(params['types']?params['types']:[]);
      this.setTypes(params['types']); // check the appropriate checkboxes
      this.setSortBy(params['sort']);
      this.getClaims();
      this.subscriptions.push(this.searchTermStream
        .pipe(debounceTime(300), distinctUntilChanged())
        .subscribe((term: string) => {
          this.keyword = term;
          this.page = 1;
          this.goTo();
        }));
      this.subscriptions.push(this.filterForm.get('entities').valueChanges.subscribe(value => {
        this.goTo();
      }));
      this.subscriptions.push(this.filterForm.get('sort').valueChanges.subscribe(value => {
        this.goTo();
      }));
    }));
  }
  
  ngOnDestroy() {
    this.subscriptions.forEach(subscription => {
      if (subscription instanceof Subscriber) {
        subscription.unsubscribe();
      }
    });
    if (this.subResults) {
      this.subResults.unsubscribe();
    }
  }
  
  getClaims() {
    let types = '';
    for (let type of this.entities) {
      types += (types.length > 0 ? '&' : '') + "types=" + type;
    }
    this.loading = true;
    if (this.subResults) {
      this.subResults.unsubscribe();
    }
    if (this.fetchBy == "Project") {
      this.subResults = this._claimService.getClaimsByProject(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
        data => {
          this.manageAPIData(data);
          this.loading = false;
        },
        err => {
          this.handleErrors(err, "Error getting claims for project with id: " + this.fetchId);
        }
      );
    } else if (this.fetchBy == "User") {
      this.subResults = this._claimService.getClaimsByUser(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
        data => {
          this.manageAPIData(data);
          this.loading = false;
        },
        err => {
          this.handleErrors(err, "Error getting claims for user with id: " + this.fetchId);
          this.loading = false;
        }
      );
    } else if (this.fetchBy == "Result") {
      this.subResults = this._claimService.getClaimsByResult(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
        data => {
          this.manageAPIData(data);
          this.loading = false;
        },
        err => {
          this.handleErrors(err, "Error getting claims for entity with id: " + this.fetchId);
          this.loading = false;
        }
      );
    } else if (this.fetchBy == "Context") {
      this.subResults = this._claimService.getClaimsBycontext(this.size, this.page, this.fetchId, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
        data => {
          this.manageAPIData(data);
          this.loading = false;
        },
        err => {
          this.handleErrors(err, "Error getting claims for context with id: " + this.fetchId);
          this.loading = false;
        }
      );
    } else {
      this.subResults = this._claimService.getClaims(this.size, this.page, this.keyword, this.filterForm.get("sort").value.sort, this.filterForm.get("sort").value.descending, types, this.properties.claimsAPIURL).subscribe(
        data => {
          this.manageAPIData(data);
          this.loading = false;
        },
        err => {
          this.handleErrors(err, "Error getting claims");
          this.loading = false;
        }
      );
    }
  }
  
  manageAPIData(data) {
    this.claims = data.data;
    this.resultsNum = +data.total;
  }
  
  handleErrors(err, message) {
    NotificationHandler.rise(message, "danger");
    console.error("Display Claims (component): " + message + " " + (err && err.error ? err.error : ''));
  }
  
  goTo(page: number = 1) {
    this.page = page;
    this.location.go(location.pathname, this.getParametersString());
    HelperFunctions.scroll();
    this.getClaims();
  }
  
  getParametersString() {
    let params = '';
    params += (this.page == 1 ? "" : (params.length > 0 ? '&' : '') + "page=" + this.page);
    params += (this.size == 10 ? "" : (params.length > 0 ? '&' : '') + "size=" + this.size);
    let types = "";
    for (let type of this.entities) {
      types += (types.length > 0 ? ',' : '') + type;
    }
    params += (this.entities.length > 0) ? (params.length > 0 ? '&' : '') + "types=" + types : "";
    if (this.isAdmin) {
      params += (this.fetchBy == 'All' ? "" : (params.length > 0 ? '&' : '') + "fetchBy=" + this.fetchBy);
      params += (this.fetchId == '' ? "" : (params.length > 0 ? '&' : '') + "fetchId=" + this.fetchId);
    }
    params += (this.filterForm.get("sort").value.sort == 'date' && this.filterForm.get("sort").value.descending ? "" : (params.length > 0 ? '&' : '') + "sort=" + this.filterForm.get("sort").value.sort + "-" + this.filterForm.get("sort").value.descending);
    params += (this.keyword == '' ? "" : (params.length > 0 ? '&' : '') + "keyword=" + this.keyword);
    if (this.communityId != null) {
      params += "&communityId=" + this.communityId;
    }
    return params;
  }
  
  setSortBy(sortby: string) {
    let sort = "date";
    let desc = "desc";
    if (sortby && sortby.split("-").length == 2) {
      sort = sortby.split("-")[0];
      desc = sortby.split("-")[1];
    }
    
    let option = this.sortOptions.find(option => option.value.sort == sort && ((option.value.descending && desc == "desc") || (!option.value.descending && desc == "asc")));
    this.filterForm.get("sort").setValue(option ? option.value : this.sortOptions[0].value);
  }
  
  setTypes(typesParam: string) {
    for (let type of typesParam ? typesParam.split(',') : []) {
      this.entities.push(type);
    }
  }
  
  changeKeyword() {
    if (this.filterForm.get("keyword") && (this.filterForm.get("keyword").value?.length >= 3 || this.filterForm.get("keyword").value?.length == 0)) {
      this.searchTermStream.next(this.filterForm.get("keyword").value);
    }
  }
  
  select(value: string, event, dropdownFilter: DropdownFilterComponent) {
    if(event.target instanceof HTMLInputElement) {
      dropdownFilter.closeDropdown();
      if(event.target.checked && !this.entities.find(entity => value === entity)) {
        this.entities.push(value);
      } else if(!event.target.checked) {
        let index = this.entities.indexOf(value);
        if(index !== -1) {
          this.entities.splice(index, 1);
        }
      }
      this.filterForm.get('entities').setValue(this.entities);
    }
  }
  
  isSelected(value: string) {
    return this.filterForm && this.filterForm.get('entities').value.find(entity => entity === value);
  }
  
  deleteOpen(index: number = null) {
    this.index = index;
    this.deleteModal.alertTitle = 'Delete Confirmation';
    this.deleteModal.message = 'Are you sure you want to delete ' + (this.index != null ? '1' : this.selected.length) + ' link(s)?';
    this.deleteModal.okButtonText = 'Yes';
    this.deleteModal.open();
  }
  
  delete() {
    let claimsToBeDeleted = ((this.index != null) ? [this.claims[this.index].id] : this.selected.map(claim => claim.id));
    console.log(claimsToBeDeleted);
    this.subscriptions.push(this._claimService.deleteBulk(claimsToBeDeleted, this.properties.claimsAPIURL).subscribe(
      res => {
        if (this.index != null) {
          this.claims.splice(this.index, 1);
          this.resultsNum = this.resultsNum - 1;
          NotificationHandler.rise('Link has been deleted successfully');
        } else {
          claimsToBeDeleted.forEach(claimId => {
            this.claims.splice(this.claims.findIndex((id) => id == claimId), 1);
          });
          this.resultsNum = this.resultsNum - claimsToBeDeleted.length;
          NotificationHandler.rise(claimsToBeDeleted.length + ' links have been deleted successfully');
        }
        this.selected = [];
        let goToPage = this.page;
        if (this.totalPages(this.resultsNum) < this.page && this.page > 0) {
          goToPage = this.page - 1;
        }
        this.goTo(goToPage);
      }, err => {
        this.handleErrors(err, "Error deleting claim with id: " + this.claims[this.index].id);
      }
    ));
  }
  
  pageChange($event) {
    let page: number = +$event.value;
    this.goTo(page);
  }
  
  isClaimAvailable(claim: ClaimDBRecord): boolean {
    //claim.target.collectedFrom == "infrastruct_::openaire" &&
    let lastUpdateDate = new Date((this.lastIndexDate != null) ? this.lastIndexDate : this.properties.lastIndexUpdate);
    let lastUpdateDateStr = Dates.getDateToString(lastUpdateDate);
    let claimDate = new Date(claim.date);
    let claimDateStr = Dates.getDateToString(claimDate);
    if (claimDateStr < lastUpdateDateStr) {
      return true;
    } else {
      return claim.target.collectedFrom != "infrastruct_::openaire";
    }
  }
  
  totalPages(totalResults: number): number {
    let totalPages: any = totalResults / (this.size);
    if (!(Number.isInteger(totalPages))) {
      totalPages = (parseInt(totalPages, 10) + 1);
    }
    return totalPages;
  }

  selectClaim(item: any, event) {
    let value = event.currentTarget.checked;
    if (value) {
      this.selected.push(item);
    } else {
      for (var _i = 0; _i < this.selected.length; _i++) {
        let claim = this.selected[_i];
        if (claim['id'] == item.id) {
          this.selected.splice(_i, 1);
        }
      }
    }
  }

  selectAll(event) {
    let value = event.currentTarget.checked;
    if (value) {
      this.selected = [];
      for (let _i = 0; _i < this.claims.length; _i++) {
        let claim = this.claims[_i];
        this.selected.push(claim);
      }
    } else {
      this.selected = [];
    }
  }

  isSelectedClaim(id: string) {
    for (let _i = 0; _i < this.selected.length; _i++) {
      let claim = this.selected[_i];
      if (claim['id'] == id) {
        return true;
      }
    }
    return false;
  }

  private updateDescription(description: string) {
    this._meta.updateTag({content: description}, "name='description'");
    this._meta.updateTag({content: description}, "property='og:description'");
  }
  
  private updateTitle(title: string) {
    var _prefix = "";
    if (!this.communityId) {
      _prefix = "OpenAIRE | ";
    }
    var _title = _prefix + ((title.length > 50) ? title.substring(0, 50) : title);
    if (this.myClaims) {
      this._title.setTitle(_title);
    }
    this._meta.updateTag({content: _title}, "property='og:title'");
  }
  
  private updateUrl(url: string) {
    this._meta.updateTag({content: url}, "property='og:url'");
  }
}
