import { inject, Injectable } from '@angular/core';
import {
  ListResponseArgsOfItemDTO,
  ResponseArgsOfUISettingsDTO,
  SearchService,
} from '@generated/swagger/cat-search-api';
import { firstValueFrom, map } from 'rxjs';
import {
  catchResponseArgsErrorPipe,
  ResponseArgsError,
  takeUntilAborted,
  takeUntilKeydownEscape,
} from '@isa/common/data-access';
import { Item, QuerySettings } from '../models';
import {
  SearchByTermInput,
  SearchByTermSchema,
} from '../schemas/catalouge-search.schemas';
import { ListResponseArgs } from '@isa/common/data-access';
import { QueryTokenInput, QueryTokenSchema } from '../schemas';
import { logger } from '@isa/core/logging';
import { HttpErrorResponse } from '@angular/common/http';

@Injectable({ providedIn: 'root' })
export class CatalougeSearchService {
  #searchService = inject(SearchService);
  #logger = logger(() => ({ service: 'CatalougeSearchService' }));

  async searchByEans(
    ean: string[],
    abortSignal?: AbortSignal,
  ): Promise<Item[]> {
    this.#logger.info('Searching items by EANs', () => ({ count: ean.length }));

    let req$ = this.#searchService.SearchByEAN(ean).pipe(
      map((res) => {
        if (res.error) {
          throw new Error(res.message);
        }

        return res.result as Item[];
      }),
    );

    if (abortSignal) {
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    try {
      const items = await firstValueFrom(req$);
      this.#logger.debug('Successfully fetched items by EANs', () => ({
        count: items.length,
      }));
      return items;
    } catch (error) {
      this.#logger.error(
        'Error fetching items by EANs',
        error as Error,
        () => ({
          eanCount: ean.length,
        }),
      );
      return [];
    }
  }

  async searchByTerm(
    params: SearchByTermInput,
    abortSignal: AbortSignal,
  ): Promise<ListResponseArgs<Item>> {
    const { searchTerm, skip, take } = SearchByTermSchema.parse(params);

    const req$ = this.#searchService
      .SearchSearch({
        input: {
          qs: searchTerm,
        },
        skip,
        take,
        doNotTrack: true,
      })
      .pipe(takeUntilAborted(abortSignal));

    const res = await firstValueFrom(req$);

    if (res.error) {
      throw new Error(res.message);
    }

    return res as ListResponseArgs<Item>;
  }

  async fetchLoyaltyQuerySettings(): Promise<QuerySettings> {
    this.#logger.info('Fetching loyalty query settings from API');

    const req$ = this.#searchService
      .SearchLoyaltySettings()
      .pipe(catchResponseArgsErrorPipe<ResponseArgsOfUISettingsDTO>());

    try {
      const res = await firstValueFrom(req$);
      this.#logger.debug('Successfully fetched loyalty query settings');
      return res.result as QuerySettings;
    } catch (error:
      | ResponseArgsError<ResponseArgsOfUISettingsDTO>
      | HttpErrorResponse
      | Error
      | unknown) {
      this.#logger.error('Error fetching loyalty query settings', error);
      return undefined as unknown as QuerySettings;
    }
  }

  async searchLoyaltyItems(
    params: QueryTokenInput,
    abortSignal: AbortSignal,
  ): Promise<ListResponseArgs<Item>> {
    this.#logger.info('Fetching loyalty items from API');
    const { filter, input, orderBy, skip, take } =
      QueryTokenSchema.parse(params);

    const loyaltyFilter = {
      format: '!eb;!dl',
      praemie: '1-',
      ...filter,
    };

    const req$ = this.#searchService
      .SearchSearch({
        filter: loyaltyFilter,
        input,
        orderBy,
        skip,
        take,
      })
      .pipe(
        takeUntilAborted(abortSignal),
        takeUntilKeydownEscape(),
        catchResponseArgsErrorPipe<ListResponseArgsOfItemDTO>(),
      );

    try {
      const res = await firstValueFrom(req$);
      this.#logger.debug('Successfully fetched loyalty items');
      return res as ListResponseArgs<Item>;
    } catch (error:
      | ResponseArgsError<ListResponseArgsOfItemDTO>
      | HttpErrorResponse
      | Error
      | unknown) {
      this.#logger.error('Error fetching loyalty items', error);
      return undefined as unknown as ListResponseArgs<Item>;
    }
  }
}
