import { inject, Injectable } from '@angular/core';
import { QuerySettingsDTO, ReceiptService } from '@generated/swagger/oms-api';
import { map, Observable, throwError } from 'rxjs';
import { QueryTokenInput, QueryTokenSchema } from '../schemas';
import { ReceiptListItem } from '../models';
import { ListResponseArgs } from '@isa/common/data-access';
import {
  ReturnParseQueryTokenError,
  ReturnSearchSearchError,
} from '../errors/return-search.error';
import { ZodError } from 'zod';

@Injectable({ providedIn: 'root' })
export class ReturnSearchService {
  #receiptService = inject(ReceiptService);

  /**
   * Fetches query settings for receipt search.
   *
   * @returns {Observable<QuerySettingsDTO>} An observable containing the query settings.
   * @throws {Error} If the query settings cannot be fetched.
   */
  querySettings(): Observable<QuerySettingsDTO> {
    return this.#receiptService.ReceiptQueryReceiptSettings().pipe(
      map((res) => {
        if (res.error || !res.result) {
          throw new Error('Failed to fetch query settings');
        }
        return res.result;
      }),
    );
  }

  /**
   * Executes a search for receipts based on the provided query token.
   *
   * @param {QueryTokenInput} queryToken - The query token containing search parameters.
   * @returns {Observable<ListResponseArgs<ReceiptListItem>>} An observable containing the search results.
   * @throws {ReturnParseQueryTokenError} If the query token is invalid.
   * @throws {ReturnSearchSearchError} If the search fails due to an API error.
   */
  search(
    queryToken: QueryTokenInput,
  ): Observable<ListResponseArgs<ReceiptListItem>> {
    try {
      queryToken = QueryTokenSchema.parse(queryToken);
    } catch (error) {
      if (error instanceof ZodError) {
        return throwError(
          () => new ReturnParseQueryTokenError(queryToken, error.message),
        );
      }
      if (error instanceof Error) {
        return throwError(
          () => new ReturnParseQueryTokenError(queryToken, error.message),
        );
      }
      return throwError(
        () => new ReturnParseQueryTokenError(queryToken, 'Unknown error'),
      );
    }

    return this.#receiptService
      .ReceiptQueryReceipt({
        queryToken,
      })
      .pipe(
        map((res) => {
          if (res.error) {
            throw new ReturnSearchSearchError(
              res.message || 'Unknown Error',
              queryToken,
              res as ListResponseArgs<ReceiptListItem>,
            );
          }

          return res as ListResponseArgs<ReceiptListItem>;
        }),
      );
  }
}
