import LZString from "lz-string";

export class FilterManagerService<T extends { [key: string]: any}> {

  filters: T;
  initialFilters: T;

  isUrlFilters: boolean;
  localStorageKey: string;

  constructor(localStorageKey: string) {
    this.localStorageKey = localStorageKey;
    this.isUrlFilters = false;
    this.filters = {} as T;
    this.initialFilters = {} as T;
  }

  hasValueChanged(): boolean {
    if(Object.keys(this.filters).length === 0) {
      return false;
    }
    return this.filters !== this.initialFilters;
  }

  resetValues(): void {
    this.filters = {} as T;
  }

  persistToLocalStorage(): void {
    function isValidValue(value: any) {
      if (typeof value === 'string') {
        return value.trim() !== '';
      }
      return value !== null && value !== undefined;
    }

    this.filters = Object.fromEntries(
      Object.entries(this.filters).filter(([_, v]) => isValidValue(v))
    ) as T;

    try {
      const filtersJson = JSON.stringify(this.filters);
      localStorage.setItem(this.localStorageKey, filtersJson);
      console.debug('Filters saved to local storage');
    } catch (e) {
      console.error('Error saving filters to local storage', e);
    }
  }

  setFiltersFromLocal(): void {
    console.debug('Loading filters from local storage');

    const savedFilters = localStorage.getItem(this.localStorageKey);
    if (savedFilters) {
      try {
        const filters: T = JSON.parse(savedFilters);
        this.applyFilters(filters);
      } catch (e) {
        console.error('Error parsing filters from local storage', e);
      }
    }
  }

  private safeParseValue(value: string): any {
    const parsedFloat = parseFloat(value);
    if (!isNaN(parsedFloat)) {
      return parsedFloat;
    }
    return value;
  }

  setFiltersFromUrl(compressedFiltersUrl: string): void {
    this.isUrlFilters = true;
    console.debug('Filters from URL', compressedFiltersUrl);

    let queryString = LZString.decompressFromBase64(compressedFiltersUrl);
    if(!queryString) {
      queryString = LZString.decompressFromBase64(decodeURIComponent(compressedFiltersUrl));
    }

    if (queryString) {
      let params = new URLSearchParams(queryString);
      let newFilters = {} as any;

      params.forEach((value, key) => {
        newFilters[key] = this.safeParseValue(value);
      });

      this.applyFilters(newFilters as T);
    }
  }

  getFiltersUrl(): string {
    let queryString = Object.entries(this.filters).reduce((acc, [key, value]) => {
      acc += `${key}=${value}&`;
      return acc;
    }, '');

    queryString = queryString.endsWith('&') ? queryString.slice(0, -1) : queryString;
    let compressToBase64 = LZString.compressToBase64(queryString);
    return encodeURIComponent(compressToBase64);
  }

  private applyFilters(filters: T): void {
    this.filters = { ...this.filters, ...filters };
  }

}
