var SearchResultsModel = function (config) {
  var self = this;
  self.config = config;
  // Props
  self.isLoading = ko.observable(true);
  self.showResults = ko.observable(false);
  self.searchParams = self.configsearchParams;
  self.items = ko.observableArray([]);
  self.filteredItems = ko.observableArray([]);
  self.totalItems = ko.computed(function () {
    return self.items().length;
  });
  self.publishedContentIdsOrder = ko.observableArray();
  self.getStatus = function (str) {
    if (str) {
      return `card-list-item-status-${str.toLowerCase().replace(/\s/g, "-")}`;
    }
    return "";
  };
  self.isEmpty = function (str) {
    if (str) {
      return str.length > 0 ? str : "-";
    }
    return "-";
  };
  self.alertMessage = ko.observable({ text: "", icon: "", type: "" });
  self.isJSON = function (str) {
    try {
      return JSON.parse(str) && !!str;
    } catch (e) {
      console.log(e);
      return false;
    }
  };
  self.attempts = ko.observable(0);
  self.showErrorMessage = function () {
    self.alertMessage({
      text: "There was an error, please try again later",
      icon: "fa-exclamation-circle",
      type: "alert-warning",
    });
  };

  // filters
  self.filters = ko.observableArray(config.filterConfig);
  self.filtersSelected = ko.observableArray([]);
  self.filtersSelected.subscribe(function (filterBy) {
    var items = self.items();
    if (filterBy.length > 0) {
      var filteredList = self.items();
      filterBy.forEach((option) => {
        if (option.prop === "_custom_filter_") {
          filteredList =
            typeof option.fn === "function" ? option.fn(items) : [];
        } else {
          filteredList = filteredList.filter(function (item) {
            // console.log('B', option.prop, option.prop === '_custom_filter_')
            if (item[option.prop] === undefined) {
              return false;
            } else if (Array.isArray(item[option.prop])) {
              if (!item[option.prop].includes(option.value)) {
                return false;
              }
            } else if (item[option.prop] !== option.value) {
              return false;
            }
            return true;
          });
        }
      });

      self.filteredItems(filteredList);
      self.currentPageRecords();
    } else {
      self.filteredItems(items);
      self.currentPageRecords();
    }
    self.currentPageIndex(1);
    self.initPagination();
  });
  self.CreateFilters = function (items) {
    var filters = [];
    if (items.length > 0) {
      self.filters().forEach(function (filter, index) {
        if (filter.prop !== "_custom_filter_") {
          var options = self.getFilterOptions(items, filter.prop);
          filters.push({
            prop: filter.prop,
            label: filter.label,
            total: options.length,
            options: options,
          });
        }
        if (filter.prop === "_custom_filter_") {
          filters.push(filter);
        }
      });
      self.filters(filters);
    }
  };
  self.getFilterOptions = function (items, key) {
    // collect each different key
    const filterItems = [
      ...new Map(items.map((item) => [item[key], item])).values(),
    ];
    // collect options for filter dropdown
    let total = 0;
    const options = [];
    filterItems.forEach((item) => {
      if (Array.isArray(item[key])) {
        item[key].forEach((value) => {
          // No duplicates
          if (!options.some((a) => a.value === value)) {
            total = items.filter((b) => {
              if (Array.isArray(b[key])) {
                return b[key].includes(value);
              }
              return false;
            });
            options.push({ value: value, text: value, total: total.length });
          }
        });
      } else if (item[key]) {
        total = items.filter((c) => c[key] === item[key]).length;
        options.push({ value: item[key], text: item[key], total: total });
      }
    });
    return options;
  };
  self.getTotalItemsByCustomFilter = function (fn) {
    if (typeof fn === "function") {
      return fn(self.items()).length;
    }
    return 0;
  };
  self.getTotalItemsByFilter = function (key, value, fn = null) {
    if (self.filtersSelected().length === 0) {
      return self.items().filter((item) => {
        if (Array.isArray(item[key])) {
          return item[key].includes(value);
        }
        return item[key] === value;
      }).length;
    }
    return self.filteredItems().filter((item) => {
      if (Array.isArray(item[key])) {
        return item[key].includes(value);
      }
      return item[key] === value;
    }).length;
  };
  self.getTotalFiltersSelected = function (prop) {
    return self.filtersSelected().filter((option) => {
      return option.prop === prop;
    }).length;
  };
  self.filterIsSelected = function (prop, value) {
    return (
      self.filtersSelected().filter((option) => {
        return option.prop === prop && option.value === value;
      }).length > 0
    );
  };
  self.clearFilters = function () {
    self.filtersSelected([]);
  };

  // Sorting
  self.sorting = ko.observable({
    prop: "",
    propType: "",
    direction: "",
  });
  self.clickSortBy = function (data, e) {
    const $el = $(e.currentTarget);
    // Toggle direction
    const currentDirection = $el.data("sortDirection");
    const newDirection =
      currentDirection === undefined || currentDirection === ""
        ? "asc"
        : currentDirection === "desc"
        ? ""
        : "desc";
    $el.data("sortDirection", newDirection);
    // set sorting
    self.sorting({
      prop: data.prop,
      propType: data.propType,
      direction: newDirection,
    });
  };
  self.getSortCSSClass = function (prop) {
    if (self.sorting().prop === prop && self.sorting().direction !== "") {
      return self.sorting().direction === "asc"
        ? "fa-arrow-up"
        : "fa-arrow-down";
    }
    return "";
  };
  self.sortBy = function (records) {
    const prop = self.sorting().prop;
    const propType = self.sorting().propType;
    const direction = self.sorting().direction;

    if (Array.isArray(records) && direction !== "") {
      switch (propType) {
        case "number":
          return records.sort(function (a, b) {
            return direction === "asc" ? a[prop] - b[prop] : b[prop] - a[prop];
          });
          break;
        case "moment.date":
          return records.sort(function (a, b) {
            if (!moment(a[prop]).isValid()) {
              return direction === "asc" ? -1 : 1;
            }
            if (!moment(b[prop]).isValid()) {
              return direction === "asc" ? 1 : -1;
            }

            return direction === "asc"
              ? moment(a[prop]).diff(b[prop])
              : moment(b[prop]).diff(a[prop]);
          });
          break;
        case "date":
          return records.sort(function (a, b) {
            if (a[prop] === undefined || a[prop] === "") {
              return 1;
            }
            if (b[prop] === undefined || b[prop] === "") {
              return -1;
            }
            // Must be a timestamp valid for Date Class
            var dateA = new Date(a[prop]).getTime();
            var dateB = new Date(b[prop]).getTime();
            return direction === "asc" ? dateB - dateA : dateB - dateA;
          });
          break;
        default: // string
          return records.sort(function (a, b) {
            const str1 =
              direction === "asc"
                ? a[prop].toLowerCase()
                : b[prop].toLowerCase();
            const str2 =
              direction === "asc"
                ? b[prop].toLowerCase()
                : a[prop].toLowerCase();
            if (str1 < str2) {
              return -1;
            }
            if (str1 > str2) {
              return 1;
            }

            // names must be equal
            return 0;
          });
          break;
      }
    }
    return records;
  };

  // paging
  self.pageSize = ko.observable(self.config.pageNum ? self.config.pageNum : 10);
  self.currentPageIndex = ko.observable(1);
  self.maxPageIndex = ko.observable(0);
  self.maxPageIndex = ko.computed(function () {
    var items =
      self.filtersSelected().length > 0 ? self.filteredItems() : self.items();
    return Math.ceil(items.length / self.pageSize());
  });
  self.initPagination = ko.computed(function () {
    if (self.maxPageIndex() > 0 && self.config.paginationElement) {
      self.config.paginationElement.pagination({
        total_pages: self.maxPageIndex(),
        next: "Next",
        prev: "Previous",
        callback: function (event, pageNum) {
          self.currentPageIndex(pageNum);
        },
      });
    }
  });

  self.currentPageRecords = ko.computed(function () {
    var currentIndex = self.currentPageIndex() - 1;
    var startIndex = self.pageSize() * currentIndex;
    var endIndex = self.pageSize() * (currentIndex + 1);
    var filtered =
      self.filtersSelected().length > 0 ? self.filteredItems() : self.items();
    var sorted = self.sortBy(filtered);
    return sorted.slice(startIndex, endIndex);
  }, this);

  self.checkDataResult = function (response) {
    const items = response.items ? response.items : response.results;
    if (Array.isArray(items)) {
      return items;
    }
    if (self.isJSON(response)) {
      return JSON.parse(response).items;
    }
    return false;
  };


  // Get search data
  self.FetchSearchItems = function (relevanceSearchResults) {
    var params = new URLSearchParams(window.location.search);
    var publishedContentIds = "";
    // limit the pageNumber to match with max items returned,currently retrun max 50 items
    var allResultsReturned =
      relevanceSearchResults.pageNumber >= 5 || self.attempts() >= 5;
    if (relevanceSearchResults) {
      var newItems = relevanceSearchResults.items.map(function (x, i) {
        return x.entityID;
      });
      var newList = self.publishedContentIdsOrder().concat(newItems);
      if (newList.length >= 50) {
        newList.length = 50;
      }
      self.publishedContentIdsOrder(newList);

      if (allResultsReturned) {
        publishedContentIds = self.publishedContentIdsOrder().join(",");
      } else {
        self.PerformRelevanceSearch(relevanceSearchResults.pageNumber + 1);
        self.attempts(self.attempts() + 1);
      }
    }
    if (allResultsReturned) {
      $.ajax({
        method: "GET",
        url:
          self.config.serviceApi +
          (params.get("q") ? window.location.search : self.config.defaultQuery),
        success: function (data) {
          var items = self.checkDataResult(data);
          if (items === false) {
            self.showErrorMessage();
          } else {
     
            if (items.length > 0) {
              if (typeof self.config.remapSearchData === "function") {
                items = self.config.remapSearchData(items); // Remap the data
              }
              self.items(items);
              self.filteredItems(items);
              self.CreateFilters(items);
              self.isLoading(false);
              self.initPagination();
              self.showResults(true);
            } else {
              self.alertMessage({
                text: `No results found for search "${params.get("q")}"`,
                icon: "fa-exclamation-circle",
                type: "alert-info",
              });
            }
          }
          self.isLoading(false);
        },
        error: function (msg) {
          if (msg.status == 200) {
            var response = JSON.parse(msg.responseText.replaceAll("\t", ""));
            console.warn(response);
          } else {
            console.warn("Fetch results failed:" + JSON.stringify(msg));
          }
          self.isLoading(false);
          self.showErrorMessage();
        },
      });
    }
  };

  self.PerformRelevanceSearch = function (pageNum, sortOption) {
    self.isLoading(true);
    var promise = shell.ajaxSafePost({
      method: "POST",
      url: self.config.performRelevanceSearchUrl,
      contentType: "application/json",
      data: JSON.stringify(
        new self.config.searchServicePayload(pageNum, sortOption)
      ),
    });
    $.when(promise).then(self.FetchSearchItems);
  };

  self.FetchItems = function () {
    self.isLoading(true);
    $.ajax({
      method: "GET",
      url: self.config.serviceApi,
      success: function (data) {
        var items = self.checkDataResult(data);
        if (items === false) {
          self.showErrorMessage();
        } else if (items.length > 0) {
          if (typeof self.config.remapSearchData === "function") {
            items = self.config.remapSearchData(items); // Remap the data
          }
          self.items(items);
          self.filteredItems(items);
          self.CreateFilters(items);
          self.isLoading(false);
          self.initPagination();
          self.showResults(true);
        }
        self.isLoading(false);
      },
      error: function (msg) {
        if (msg.status == 200) {
          var response = JSON.parse(msg.responseText.replaceAll("\t", ""));
          console.warn(response);
        } else {
          console.warn("Fetch results failed:" + JSON.stringify(msg));
        }
        self.showErrorMessage();
        self.isLoading(false);
      },
    });
  };
};
