import { inject, Injectable } from '@angular/core';
import { CommandService } from '@core/command';
import {
  FetchReceiptsByOrderItemSubsetIdsInput,
  FetchReceiptsByOrderItemSubsetIdsSchema,
  HandleCommand,
  HandleCommandSchema,
} from '../schemas';
import { logger } from '@isa/core/logging';
import { ReceiptService } from '@generated/swagger/oms-api';
import { firstValueFrom } from 'rxjs';
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
import { Receipt } from '../models';

@Injectable()
export class HandleCommandService {
  #logger = logger(() => ({ service: 'HandleCommandService' }));

  #receiptService = inject(ReceiptService);

  // TODO: Befindet sich in der alten ISA (@core/command) - Als Lib auslagern
  #commandService = inject(CommandService);

  async handle(params: HandleCommand): Promise<HandleCommand> {
    const parsed = HandleCommandSchema.parse(params);

    this.#logger.debug('Handle command', () => ({ parsed }));

    let context: HandleCommand;

    // Fetch receipts if needed for shipping note or small amount invoice printing
    if (
      parsed?.action?.command?.includes('PRINT_SHIPPINGNOTE') ||
      parsed?.action?.command === 'PRINT_SMALLAMOUNTINVOICE'
    ) {
      // Fetch receipts if not already provided
      let receipts = parsed.receipts ?? [];

      if (receipts.length === 0 && parsed.items?.length > 0) {
        const orderItemSubsetIds = parsed.items
          .map((item) => item.orderItemSubsetId)
          .filter((id): id is number => id !== undefined && id !== null);

        if (orderItemSubsetIds.length > 0) {
          receipts = await this.fetchReceiptsByOrderItemSubsetIds({
            ids: orderItemSubsetIds,
          });
        }
      }

      // Keep receipts - use params with receipts
      context = { ...parsed, receipts };
    } else {
      // Omit receipts from context
      const { receipts, ...restParams } = parsed;
      context = restParams;
    }

    // #2737 Bei Zubuchen kein Abholfachzettel ausdrucken
    let command = parsed?.action?.command ?? '';
    if (parsed?.compartmentCode && !!parsed?.action?.command) {
      command = parsed.action.command?.replace('|PRINT_COMPARTMENTLABEL', '');
    }
    return this.#commandService.handleCommand(command, context);
  }

  async fetchReceiptsByOrderItemSubsetIds(
    params: FetchReceiptsByOrderItemSubsetIdsInput,
    abortSignal?: AbortSignal,
  ) {
    const parsed = FetchReceiptsByOrderItemSubsetIdsSchema.parse(params);

    this.#logger.debug('Fetch receipts by order item subset IDs', () => ({
      parsed,
    }));

    let req$ = this.#receiptService.ReceiptGetReceiptsByOrderItemSubset({
      payload: parsed, // Payload Default from old Implementation, eagerLoading: 1 and receiptType: (1 + 64 + 128) set as Schema default
    });

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

    const res = await firstValueFrom(req$);

    if (res.error) {
      const err = new ResponseArgsError(res);
      this.#logger.error(
        'Failed to fetch receipts by order item subset IDs',
        err,
      );
      throw err;
    }

    // Mapping Logic from old implementation
    const mappedReceipts =
      res?.result?.map((r) => r.item3?.data).filter((f) => !!f) ?? [];

    return mappedReceipts as Receipt[];
  }
}
