import { inject, resource } from '@angular/core';
import { ListResponseArgs, ResponseArgsError } from '@isa/common/data-access';
import {
  orderByListItems,
  QueryTokenInput,
  RemissionItem,
  RemissionListType,
  RemissionSearchService,
  RemissionStockService,
  RemissionSupplierService,
} from '@isa/remission/data-access';
import { SearchTrigger } from '@isa/shared/filter';
import { isEan } from '@isa/utils/ean-validation';

/**
 * Creates an Angular resource for fetching remission lists.
 * Handles both standard (Pflicht) and department (Abteilung) remission lists.
 * Automatically fetches the assigned stock and supplier before loading the list.
 *
 * @function createRemissionListResource
 * @param {Function} params - Function that returns parameters for the resource
 * @param {RemissionListType} params.remissionListType - Type of remission list to fetch
 * @param {QueryTokenInput} params.queryToken - Query parameters for filtering and sorting
 * @param {SearchTrigger | 'reload' | 'initial'} params.searchTrigger - How the search was triggered, affects filter behavior
 * @returns {Resource} Angular resource that manages the remission list data
 * @throws {Error} When no current stock is available
 * @throws {Error} When no supplier is available
 *
 * @example
 * const remissionListResource = createRemissionListResource(() => ({
 *   remissionListType: RemissionListType.Pflicht,
 *   queryToken: {
 *     filter: { status: 'open' },
 *     orderBy: 'date',
 *     // ... other query parameters
 *   },
 *   searchTrigger: 'input'
 * }));
 *
 * @remarks
 * The searchTrigger parameter influences query behavior:
 * - 'scan': Clears existing filters to show scan-specific results
 * - Other triggers: Preserves existing filter state
 */
export const createRemissionListResource = (
  params: () => {
    remissionListType: RemissionListType;
    queryToken: QueryTokenInput;
    searchTrigger: SearchTrigger | 'reload' | 'initial';
  },
) => {
  const remissionSearchService = inject(RemissionSearchService);
  const remissionStockService = inject(RemissionStockService);
  const remissionSupplierService = inject(RemissionSupplierService);
  return resource({
    params,
    loader: async ({ abortSignal, params }) => {
      const assignedStock = await remissionStockService.fetchAssignedStock();

      if (!assignedStock || !assignedStock.id) {
        throw new Error('No current stock available');
      }

      const suppliers =
        await remissionSupplierService.fetchSuppliers(abortSignal);

      const firstSupplier = suppliers[0]; // Es gibt aktuell nur Blank als Supplier

      if (!firstSupplier || !firstSupplier.id) {
        throw new Error('No Supplier available');
      }

      let res: ListResponseArgs<RemissionItem> | undefined = undefined;

      const queryToken = { ...params.queryToken };
      const exactSearch = isExactSearch(queryToken, params.searchTrigger);
      const isReload = params.searchTrigger === 'reload';

      // #5273
      // #5387 Hotfix Navigation | Reload has priority over Exact Search
      if (isReload) {
        queryToken.input = {};
      } else if (exactSearch) {
        queryToken.filter = {};
        queryToken.orderBy = [];
      }

      if (
        exactSearch ||
        params.remissionListType === RemissionListType.Pflicht
      ) {
        const fetchListResponse = await remissionSearchService.fetchList(
          {
            assignedStockId: assignedStock.id,
            supplierId: firstSupplier.id,
            ...queryToken,
          },
          abortSignal,
        );
        res = fetchListResponse;
      }

      if (
        exactSearch ||
        canFetchDepartmentList(queryToken, params.remissionListType)
      ) {
        const fetchDepartmentListResponse =
          await remissionSearchService.fetchDepartmentList(
            {
              assignedStockId: assignedStock.id,
              supplierId: firstSupplier.id,
              ...queryToken,
            },
            abortSignal,
          );
        if (res) {
          // Merge results if both lists are fetched
          res.result = [
            ...(res.result || []),
            ...(fetchDepartmentListResponse.result || []),
          ];
          if (fetchDepartmentListResponse?.hits) {
            res.hits += fetchDepartmentListResponse.hits;
          }

          if (fetchDepartmentListResponse?.skip) {
            res.skip += fetchDepartmentListResponse?.skip;
          }

          if (fetchDepartmentListResponse?.take) {
            res.take += fetchDepartmentListResponse?.take;
          }
        } else {
          res = fetchDepartmentListResponse;
        }
      }

      if (res?.error) {
        throw new ResponseArgsError(res);
      }

      // #5276 Fix - Replace defaultSort Mechanism with orderBy from QueryToken if available
      const hasOrderBy = !!queryToken?.orderBy && queryToken.orderBy.length > 0;

      if (!hasOrderBy && res && res.result && Array.isArray(res.result)) {
        orderByListItems(res.result);
      }

      return res;
    },
  });
};

// #5128 #5234 Bei Exact Search soll er über Alle Listen nur mit dem Input ohne aktive Filter / orderBy suchen
/**
 * Checks if the query token is an exact search based on the search trigger.
 * An exact search is defined as:
 * - Triggered by 'scan'
 * - Or if the query token input contains a valid EAN (barcode) in 'qs'
 * @param {QueryTokenInput} queryToken - The query token containing input parameters
 * @param {SearchTrigger} searchTrigger - The trigger that initiated the search
 * @returns {boolean} True if the search is exact, false otherwise
 */
const isExactSearch = (
  queryToken: QueryTokenInput,
  searchTrigger: SearchTrigger | 'reload' | 'initial',
): boolean => {
  return searchTrigger === 'scan' || isEan(queryToken?.input?.['qs']);
};

// #5255 Performance optimization for initial department list fetch
/**
 * Checks if the query token allows fetching the department list.
 * This is true if the remission list type is 'Abteilung' and either:
 * - There is a search input (queryToken.input['qs'])
 * - There is an active filter for 'abteilungen'
 *
 * @param {QueryTokenInput} queryToken - The query token containing input and filter
 * @param {RemissionListType} remissionListType - The type of remission list being queried
 * @returns {boolean} True if the department list can be fetched, false otherwise
 */
const canFetchDepartmentList = (
  queryToken: QueryTokenInput,
  remissionListType: RemissionListType,
): boolean => {
  const hasInput = queryToken?.input?.['qs'];
  const hasAbteilungFilter = queryToken?.filter?.['abteilungen'];
  return (
    remissionListType === RemissionListType.Abteilung &&
    (hasInput || hasAbteilungFilter)
  );
};
