import { Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay, map, shareReplay } from 'rxjs/operators';
import { FilterOption, Filter } from '../models/filter';
import { RemissionSourceType } from '../types/remission-source.type';
import { RemissionFilter, RemissionSelectedFilters } from '../models';
import { InputDTO, OptionDTO, RemiService } from '@swagger/remi';

@Injectable({ providedIn: 'root' })
export class RestFilterService {
  private cachedFilters$ = new Map<string, Observable<InputDTO[]>>();

  constructor(private remiService: RemiService) {}

  mapOptionToFilterOption(option: OptionDTO): FilterOption {
    const result = {
      id: option.value,
      key: option.key,
      name: option.label,
      options: !!option.values && option.values.length > 0 ? option.values.map((i) => this.mapOptionToFilterOption(i)) : undefined,
    };

    return result;
  }

  getFilter(params: { remissionSourceType: RemissionSourceType; supplierId: number; stockId: number }): Observable<Filter[]> {
    return this.getRestFilter({
      remissionSourceType: params.remissionSourceType,
      supplierId: params.supplierId,
      stockId: params.stockId,
    }).pipe(
      map((response) =>
        response.map((input) => ({
          id: input.key,
          key: input.key,
          name: input.label,
          max: input.options.max,
          options: input.options.values.map((option) => this.mapOptionToFilterOption(option)),
        }))
      )
    );
  }

  getRestFilter(params: { remissionSourceType: RemissionSourceType; supplierId: number; stockId: number }): Observable<InputDTO[]> {
    const cacheIdentifier = params.remissionSourceType + params.supplierId;

    if (!this.cachedFilters$.get(cacheIdentifier)) {
      this.cachedFilters$.set(cacheIdentifier, this.getFiltersFromService(params).pipe(shareReplay()));
    }

    return this.cachedFilters$
      .get(cacheIdentifier)
      .pipe(map((result) => this.getSourceTypeSpecificFilters(result, params.remissionSourceType)));
  }

  createQueryRemiTokenFilter(params: {
    remissionSourceType: RemissionSourceType;
    remissionTargetName: string;
    stockId: number;
    filter: RemissionFilter;
  }): Observable<{ [key: string]: string }> {
    const queryTokenFilter: { [key: string]: string } = {};
    const filter =
      params.filter.filter[params.remissionSourceType] && params.filter.filter[params.remissionSourceType][params.remissionTargetName];

    if (!filter) {
      return of({});
    }

    for (const key in filter) {
      if (filter.hasOwnProperty(key) && Array.isArray(filter[key])) {
        const values = filter[key].filter((value) => !!value);
        queryTokenFilter[key] = values.join(';');
      }
    }

    return of(queryTokenFilter);
  }

  getSourceTypeSpecificFilters(inputs: InputDTO[], remissionSourceType: RemissionSourceType): InputDTO[] {
    return remissionSourceType === 'zentral' ? inputs : inputs.filter((option) => option.key !== 'aktionen');
  }

  private getFiltersFromService(params: {
    remissionSourceType: RemissionSourceType;
    supplierId: number;
    stockId: number;
  }): Observable<InputDTO[]> {
    let filter$: Observable<InputDTO[]>;
    const filterQuery: RemiService.RemiGetPflichtremissionFilter2Params = {
      stockId: params.stockId,
      supplierId: params.supplierId,
    };

    if (params.remissionSourceType === 'zentral') {
      filter$ = this.remiService.RemiGetPflichtremissionFilter2(filterQuery).pipe(map((response) => response.result));
    } else {
      filter$ = this.remiService.RemiGetUeberlaufFilter(filterQuery).pipe(map((response) => response.result));
    }

    return filter$;
  }

  checkFilterValidity(filter: RemissionSelectedFilters): boolean {
    const isValidRemissionSelectedFilter = filter.hasOwnProperty('zentral') && filter.hasOwnProperty('ueberlauf');

    return isValidRemissionSelectedFilter;
  }

  resetRemissionSelectedFilters(): RemissionSelectedFilters {
    return {
      ueberlauf: {
        Blank: {},
        ZL: {},
      },
      zentral: {
        Blank: {},
        ZL: {},
      },
    };
  }

  getSelectedFilters(filter: RemissionFilter): { [filterId: string]: string[] } {
    return (filter.filter && filter.filter[filter.source] && filter.filter[filter.source][filter.target.name]) || {};
  }
}
