import {ChangeDetectorRef, Component, EventEmitter, Input, Output, ViewChild} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {AdvancedField, Filter} from './searchUtils/searchHelperClasses.class';
import {SearchDataprovidersService} from '../services/searchDataproviders.service';
import {ErrorCodes} from '../utils/properties/errorCodes';
import {ErrorMessagesComponent} from '../utils/errorMessages.component';
import {OpenaireEntities, SearchFields} from '../utils/properties/searchFields';
import {SearchCustomFilter, SearchUtilsClass} from './searchUtils/searchUtils.class';

import {EnvProperties} from '../utils/properties/env-properties';
import {NewSearchPageComponent, SearchForm} from "./searchUtils/newSearchPage.component";
import {DatasourcesHelperClass} from "./searchUtils/datasourcesHelper.class";
import {properties} from "../../../environments/environment";
import {RefineResultsUtils} from "../services/servicesUtils/refineResults.class";
import {RefineFieldResultsService} from "../services/refineFieldResults.service";


@Component({
    selector: 'search-dataproviders',
    template: `
    <new-search-page
      pageTitle="{{(simpleView?'':'Advanced ')}} Find research {{ pageTitle }}"
      [entityType]=entityType
      [type]="typeName"
      [results]="results"
      [searchUtils]="searchUtils"
      [sortedByChanged]="searchUtils.sortBy"  
      [fieldIds]="fieldIds" [fieldIdsMap]="fieldIdsMap" [selectedFields]="selectedFields"
      [staticFields]="staticFields" [staticFilters]="staticFilters"
      [staticFieldValues]="staticFieldValues"
      [csvParams]="csvParams" [csvPath]="csvPath"
      [simpleSearchLink]="simpleSearchLink" [advancedSearchLink]="advancedSearchLink"
      [disableForms]="disableForms"
      [disableRefineForms]="disableRefineForms"
      [loadPaging]="loadPaging"
      [oldTotalResults]="oldTotalResults"
      [openaireLink]=openaireLink
      [includeOnlyResultsAndFilter]="includeOnlyResultsAndFilter" [hasPrefix]="hasPrefix"
      [searchForm]="searchForm"
      [entitiesSelection]="false"  [showSwitchSearchLink]="showSwitchSearchLink"  
      [filters]="filters"
      [simpleView]="simpleView" formPlaceholderText="Search by name, description, subject..." 
      [showResultCount]="true" [showIndexInfo]="type!='deposit'"
      [tableViewLink]="tableViewLink"
      [sort]="false" [showBreadcrumb]="showBreadcrumb" [basicMetaDescription]="metaDescription"
      (filterRequestAll)="filterRequestedAll($event)">

    </new-search-page>

    `
 })

export class SearchDataProvidersComponent {
  private errorCodes: ErrorCodes;
  private errorMessages: ErrorMessagesComponent;
  @Input() customFilters: SearchCustomFilter[] = null;
  @Input()
  set customFilter(customFilter: SearchCustomFilter | SearchCustomFilter[]) {
    if(!Array.isArray(customFilter)) {
      this.customFilters = customFilter?[customFilter]:null;
    }else{
      this.customFilters = customFilter;
    }
  }  @Input() tableViewLink;
  @Input() searchForm: SearchForm = {class: 'search-form', dark: true};
  public results =[];
  public filters =[];
  public searchUtils:SearchUtilsClass = new SearchUtilsClass();
  public searchFields:SearchFields = new SearchFields();

  public fieldIds:  string[] = this.searchFields.DATASOURCE_ADVANCED_FIELDS;
  public fieldIdsMap= this.searchFields.DATASOURCE_FIELDS;
  public selectedFields:AdvancedField[] =  [];

  public resourcesQuery = "(oaftype exact datasource)";
  public csvParams: string;
  public disableForms: boolean = false;
  public disableRefineForms: boolean = false;
  public loadPaging: boolean = true;
  public oldTotalResults: number = 0;
  public pagingLimit: number = 0;
  properties:EnvProperties;
  public openaireEntities = OpenaireEntities;
  @Input() type: "all" | "registries" | "journals" | "compatible" | "deposit" | "services" = "all";
  @Input() entityType: "dataprovider" | "service" = "dataprovider";
  @Input() typeName = OpenaireEntities.DATASOURCES;
  public refineFields: string[];
  pageTitle;
  @ViewChild(NewSearchPageComponent, { static: true }) searchPage: NewSearchPageComponent;
  @Input() simpleView: boolean = true;
  @Input() simpleSearchLink: string = "";
  advancedSearchLink: string = "";
  csvPath: string = "";
  @Input() hasPrefix: boolean = true;
  @Input() openaireLink: string = null;
  @Input() includeOnlyResultsAndFilter: boolean = false;
  @Output() searchPageUpdates = new EventEmitter();
  @Input() showSwitchSearchLink:boolean;
  @Input() showBreadcrumb: boolean = false;
  subs: any[] = [];
  searchResultsSub: any;
  searchFiltersSub: any;
  metaDescription = [];

  public staticFields: string[] = [];
  public staticFieldValues = this.searchFields.DATASOURCE_STATIC_FIELD_VALUES;
  public staticFilters = [];


  private refineQuery: string = "";

  constructor (private route: ActivatedRoute, private _searchDataProvidersService: SearchDataprovidersService,
               private _refineFieldsResultsService: RefineFieldResultsService,
               private cdr: ChangeDetectorRef) {
    this.results =[];
    this.errorCodes = new ErrorCodes();
    this.errorMessages = new ErrorMessagesComponent();
    this.searchUtils.status = this.errorCodes.LOADING;

    this.searchFields.sortFieldsByName(this.fieldIds, this.fieldIdsMap);
  }
  ngOnInit() {
    this.refineFields = DatasourcesHelperClass.getrefineFields(this.type);
    this.staticFields = this.entityType == "service" ? this.searchFields.DATASOURCE_STATIC_FIELDS : [];
    this.staticFilters = RefineResultsUtils.parse(this.staticFieldValues, this.staticFields, this.entityType, "search", true);

    this.pageTitle = DatasourcesHelperClass.getTitle(this.type);
    this.metaDescription = DatasourcesHelperClass.getDescription(this.type)
    if(this.showSwitchSearchLink == null){
      this.showSwitchSearchLink = (this.type == "all" || this.type == "services");
    }
    this.properties= properties;
    this.csvPath = this.entityType == "service" ? OpenaireEntities.SERVICES_FILE : OpenaireEntities.DATASOURCES_FILE;
    if (!this.simpleSearchLink) {
      this.simpleSearchLink = this.entityType == "service" ? this.properties.searchLinkToServices : this.properties.searchLinkToDataProviders;
    }
    this.advancedSearchLink = this.entityType == "service" ? this.properties.searchLinkToAdvancedServices : this.properties.searchLinkToAdvancedDataProviders;
    this.searchUtils.baseUrl = (this.simpleView)?this.simpleSearchLink:this.advancedSearchLink;
    this.pagingLimit = properties.pagingLimit;
    let firstLoad = true;
    this.subs.push(this.route.queryParams.subscribe(params => {
     this.loadPaging = true;
     if(params['page'] && this.searchUtils.page != params['page']) {
       this.loadPaging = false;
       this.oldTotalResults = this.searchUtils.totalResults;
     }
     var refine = true;
      if(this.searchPage.searchUtils.refineStatus == this.errorCodes.DONE) {

        if (params['page'] != undefined && this.filters && !firstLoad && this.searchUtils.page != +params['page']) {
          refine = false;
        }

        if (params['size'] != undefined && this.filters && !firstLoad && this.searchUtils.size != params['size']) {
          refine = false;
        }
      }

      let page = (params['page']=== undefined)?0:+params['page'];
      this.searchUtils.page = ( page < 1 ) ? 1 : page;

      this.searchUtils.validateSize(params['size']);
      this.searchPage.fieldIds = this.fieldIds;
      this.selectedFields =[];
      if(this.type == "deposit"){
        this.searchPage.keywordFields = this.searchFields.DEPOSIT_DATASOURCE_KEYWORD_FIELDS;
        this.searchPage.usedBy = "deposit";
      }
      this.searchPage.prepareSearchPage(this.fieldIds, this.selectedFields, this.refineFields, [],this.staticFields, this.fieldIdsMap,this.customFilters,params, this.entityType);
      if(refine) {
        this._getFilters(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(params), this.searchUtils.page, 0, true, this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
      } else {
        this.searchUtils.refineStatus = this.errorCodes.DONE;
      }
      this.getResults(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(params),  this.searchUtils.page, this.searchUtils.size, refine, this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad));
      firstLoad = false;

      this.refineQuery = this.searchPage.getSearchAPIQueryForRangeFields(params)+this.searchPage.getSearchAPIQueryForRefineFields(params, firstLoad);
    }));
  }
  ngOnDestroy() {
    if(this.searchResultsSub) {
      this.searchResultsSub.unsubscribe();
    }
    if(this.searchFiltersSub) {
      this.searchFiltersSub.unsubscribe();
    }
    for (let sub of this.subs) {
      sub.unsubscribe();
    }
  }

  public _getFilters(parameters:string, page: number, size: number, refine: boolean, refineFieldsFilterQuery = null){
    if (page <= this.pagingLimit || this.searchUtils.refineStatus == this.errorCodes.LOADING) {
      this.searchUtils.refineStatus = this.errorCodes.LOADING;
      this.disableRefineForms = true;
      this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});

      let datasourceQueryPrefix = DatasourcesHelperClass.getQueryPrefix(this.type);
      let isDeposit: boolean = (this.type == "deposit");
      let parametersFull;
      let refineQueryFull;
      if(isDeposit) {
        parametersFull = datasourceQueryPrefix +(datasourceQueryPrefix.length > 0 && parameters.length > 0 ?' and (':'') + parameters +(datasourceQueryPrefix.length > 0 && parameters.length > 0 ?' ) ':'');
        refineQueryFull = refineFieldsFilterQuery;
      } else {
        parametersFull = parameters;
        refineQueryFull = refineFieldsFilterQuery+(refineFieldsFilterQuery.length > 0 && datasourceQueryPrefix.length >0 ? "&" : "")+(datasourceQueryPrefix.length>0 ? "fq=" : "")+datasourceQueryPrefix;
      }
      this.searchFiltersSub = this._searchDataProvidersService.advancedSearchDataproviders( parametersFull,  page, size, this.properties, (refine /*&& (this.type=="all" || this.type == "deposit")*/) ? this.searchPage.getRefineFieldsQuery() : null, this.searchPage.getFields(), refineQueryFull, isDeposit, true)
      //.switchMap(
        .subscribe(
          data => {
            let totalResults = data[0];
            let filters = data[2];
            this.filtersReturned(refine, filters, totalResults, page);
          },
          err => {
            this.filters = this.searchPage.prepareFiltersToShow([], 0);
            this.staticFilters = this.searchPage.prepareStaticFiltersToShow();

            this.handleError("Error getting refine filters for "+OpenaireEntities.DATASOURCES+": ", err);
            this.searchUtils.refineStatus = this.errorMessages.getErrorCode(err.status);

            this.disableRefineForms = false;
            this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})
          }
        );
    }
  }

  public filtersReturned(refine: boolean, filters: Filter[], totalResults, page: number) {
    if (refine) {
      this.filters = this.searchPage.prepareFiltersToShow(filters, totalResults);
      this.staticFilters = this.searchPage.prepareStaticFiltersToShow();
    }
    this.searchUtils.refineStatus = this.errorCodes.DONE;
    if(totalResults == 0) {
      this.searchUtils.refineStatus = this.errorCodes.NONE;
    }

    if (this.searchUtils.refineStatus == this.errorCodes.DONE) {
      // Page out of limit!!!
      let totalPages: any = totalResults / (this.searchUtils.size);
      if (!(Number.isInteger(totalPages))) {
        totalPages = (parseInt(totalPages, 10) + 1);
      }
      if (totalPages < page) {
        this.searchUtils.refineStatus = this.errorCodes.OUT_OF_BOUND;
      }
    }

    if(this.searchUtils.refineStatus != this.errorCodes.DONE && this.searchUtils.status != this.searchUtils.refineStatus) {
      if (this.searchResultsSub) {
        this.searchResultsSub.unsubscribe();
      }
      this.resultsReturned(refine, [], totalResults, page);
    }

    this.disableRefineForms = false;
    this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils})

  }

  public getResults(parameters:string, page: number, size: number, refine: boolean, refineFieldsFilterQuery = null){
    if(page > this.pagingLimit ) {
      size=0;
    }
    if(page <= this.pagingLimit  || this.searchUtils.status == this.errorCodes.LOADING) {
     
      this.csvParams = (parameters ? ("&fq=("+parameters) : "") + (parameters ? ")" : "");
      this.csvParams += (refineFieldsFilterQuery ? refineFieldsFilterQuery : "");

      this.searchUtils.status = this.errorCodes.LOADING;
      this.disableForms = true;
      this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});

      this.results = [];
      this.searchUtils.totalResults = 0;

      let datasourceQueryPrefix = DatasourcesHelperClass.getQueryPrefix(this.type);
      let isDeposit: boolean = (this.type == "deposit");
      let parametersFull;
      let refineQueryFull;
      if(isDeposit) {
        parametersFull = datasourceQueryPrefix +(datasourceQueryPrefix.length > 0 && parameters.length > 0 ?' and (':'') + parameters +(datasourceQueryPrefix.length > 0 && parameters.length > 0 ?' ) ':'');
        refineQueryFull = refineFieldsFilterQuery;
      } else {
        parametersFull = parameters;
        refineQueryFull = refineFieldsFilterQuery+(refineFieldsFilterQuery.length > 0 && datasourceQueryPrefix.length >0 ? "&" : "")+(datasourceQueryPrefix.length>0 ? "fq=" : "")+datasourceQueryPrefix;
      }
      this.searchResultsSub = this._searchDataProvidersService.advancedSearchDataproviders( parametersFull,  page, size, this.properties, null, this.searchPage.getFields(), refineQueryFull, isDeposit).subscribe(
        data => {
          let totalResults = data[0];
          let results = data[1];
          this.resultsReturned(refine, results, totalResults, page);
          },
          err => {
              //console.log(err);
              this.handleError("Error getting "+OpenaireEntities.DATASOURCES, err);
              this.searchUtils.status = this.errorMessages.getErrorCode(err.status);

              //TODO check erros (service not available, bad request)
              // if( ){
              //   this.searchUtils.status = errorCodes.ERROR;
              // }
              //var errorCodes:ErrorCodes = new ErrorCodes();
              //this.searchUtils.status = errorCodes.NOT_AVAILABLE;
              /*if(err.status == '404') {
                this.searchUtils.status = this.errorCodes.NOT_FOUND;
              } else if(err.status == '500') {
                this.searchUtils.status = this.errorCodes.ERROR;
              } else {
                this.searchUtils.status = this.errorCodes.NOT_AVAILABLE;
              }*/
              //this.searchPage.closeLoading();
              this.disableForms = false;
            this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});
            this.searchPage.hideFilters = false;
          }
        );
      }
  }

  public resultsReturned(refine: boolean, results: any, totalResults, page: number) {
    this.searchUtils.totalResults = totalResults;
    this.results = results;
    if(!refine) {
      this.searchPage.buildPageURLParameters(this.filters, [], this.staticFilters,  false);
    }

    this.searchPage.hideFilters = false;

    this.searchUtils.status = this.errorCodes.DONE;
    if (this.searchUtils.totalResults == 0) {
      this.searchUtils.status = this.errorCodes.NONE;
    }

    if (this.searchUtils.status == this.errorCodes.DONE) {
      // Page out of limit!!!
      let totalPages: any = this.searchUtils.totalResults / (this.searchUtils.size);
      if (!(Number.isInteger(totalPages))) {
        totalPages = (parseInt(totalPages, 10) + 1);
      }
      if (totalPages < page) {
        this.searchUtils.totalResults = 0;
        this.searchUtils.status = this.errorCodes.OUT_OF_BOUND;
      }
    }

    if(this.searchUtils.status != this.errorCodes.DONE && this.searchUtils.refineStatus != this.searchUtils.status) {
      if(this.searchFiltersSub) {
        this.searchFiltersSub.unsubscribe();
      }
      this.filtersReturned(refine, [], totalResults, page);
    }

    this.disableForms = false;
    this.searchPageUpdates.emit({disableForms: this.disableForms, disableRefineForms: this.disableRefineForms, searchUtils: this.searchUtils});

  }

  private handleError(message: string, error) {
    console.error(OpenaireEntities.DATASOURCES+" advanced Search Page: "+message, error);
  }

  public filterRequestedAll(oldFilter: Filter) {
    let fieldsStr: string = "&fields=" + oldFilter.filterId+"&refine=true";

    this.searchFiltersSub = this._searchDataProvidersService.advancedSearchDataproviders(this.searchPage.getSearchAPIQueryForAdvancedSearhFields(), 1, 0, properties, fieldsStr, [oldFilter.filterId], this.refineQuery).subscribe(
    // this.searchFiltersSub = this._refineFieldsResultsService.getAllRefineFieldResultsByFieldName(oldFilter.filterId, this.entityType, this.properties, this.refineQuery).subscribe(
      res => {
        let filter: Filter = res[2][0];
        if(filter.values.length == 0) {
          filter = oldFilter;
          filter.countAllValues = 0;
        } else {
          filter.countAllValues = filter.values.length;
          // console.log(filter);
          for (let value of filter.values) {
            for (let oldValue of oldFilter.values) {
              if (oldValue.id == value.id && oldValue.selected) {
                value.selected = true;
                break;
              }
            }
          }
        }

        let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == filter.filterId);
        filter.isViewAllOpen = true;
        this.filters[index] = filter;
        this.cdr.detectChanges();
      },
      error => {
        let index: number = this.filters.findIndex((fltr: Filter) => fltr.filterId == oldFilter.filterId);
        oldFilter.countAllValues = 0;
        this.filters[index] = oldFilter;
        this.cdr.detectChanges();
      }
    )
  }
}
