import { inject, Injectable } from '@angular/core';
import { ReturnService } from '@generated/swagger/inventory-api';
import {
  ResponseArgs,
  ResponseArgsError,
  takeUntilAborted,
} from '@isa/common/data-access';
import { firstValueFrom } from 'rxjs';
import { RemissionStockService } from './remission-stock.service';
import { Return } from '../models/return';
import {
  AddReturnItem,
  AddReturnItemSchema,
  AddReturnSuggestionItem,
  AddReturnSuggestionItemSchema,
  AssignPackage,
  CreateReceipt,
  CreateReturn,
  CreateReturnSchema,
  FetchRemissionReturnReceiptsParams,
  FetchRemissionReturnReceiptsSchema,
  FetchReturnParams,
  FetchReturnSchema,
  UpdateItemImpediment,
  UpdateItemImpedimentSchema,
} from '../schemas';
import {
  CreateRemission,
  Receipt,
  ReceiptReturnSuggestionTuple,
  ReceiptReturnTuple,
  RemissionItemType,
  ReturnItem,
  ReturnSuggestion,
} from '../models';
import { logger } from '@isa/core/logging';
import { RemissionSupplierService } from './remission-supplier.service';

/**
 * Service responsible for managing remission return receipts.
 * Handles fetching completed and incomplete return receipts from the inventory API.
 *
 * @class RemissionReturnReceiptService
 * @injectable
 *
 * @example
 * // Inject the service
 * constructor(private remissionReturnReceiptService: RemissionReturnReceiptService) {}
 *
 * // Fetch completed receipts
 * const completedReceipts = await this.remissionReturnReceiptService
 *   .fetchCompletedRemissionReturnReceipts();
 */
@Injectable({ providedIn: 'root' })
export class RemissionReturnReceiptService {
  /** Private instance of the inventory return service */
  #returnService = inject(ReturnService);
  /** Private instance of the remission stock service */
  #remissionStockService = inject(RemissionStockService);
  /** Private instance of the remission supplier service */
  #remissionSupplierService = inject(RemissionSupplierService);
  /** Private logger instance */
  #logger = logger(() => ({ service: 'RemissionReturnReceiptService' }));

  /**
   * Fetches remission return receipts based on the provided parameters.
   * Validates parameters using FetchRemissionReturnReceiptsSchema before making the request.
   *
   * @param {FetchRemissionReturnReceiptsParams} params - The parameters for fetching the receipts
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<Return[]>} An array of remission return receipts
   * @throws {ResponseArgsError} When the API request fails
   */
  async fetchRemissionReturnReceipts(
    params: FetchRemissionReturnReceiptsParams,
    abortSignal?: AbortSignal,
  ): Promise<Return[]> {
    this.#logger.debug('Fetching completed remission return receipts');

    const { start, returncompleted } =
      FetchRemissionReturnReceiptsSchema.parse(params);

    const assignedStock =
      await this.#remissionStockService.fetchAssignedStock(abortSignal);

    this.#logger.info('Fetching completed returns from API', () => ({
      stockId: assignedStock.id,
      startDate: start?.toISOString(),
    }));

    let req$ = this.#returnService.ReturnQueryReturns({
      stockId: assignedStock.id,
      queryToken: {
        filter: { returncompleted: returncompleted ? 'true' : 'false' },
        start: start?.toISOString(),
        eagerLoading: 3,
      },
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to fetch completed returns',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const returns = (res?.result as Return[]) || [];
    this.#logger.debug('Successfully fetched completed returns', () => ({
      returnCount: returns.length,
    }));

    return returns;
  }

  // /**
  //  * Fetches a specific remission return receipt by receipt and return IDs.
  //  * Validates parameters using FetchRemissionReturnReceiptSchema before making the request.
  //  *
  //  * @async
  //  * @param {FetchRemissionReturnParams} params - The receipt and return identifiers
  //  * @param {FetchRemissionReturnParams} params.receiptId - ID of the receipt to fetch
  //  * @param {FetchRemissionReturnParams} params.returnId - ID of the return containing the receipt
  //  * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
  //  * @returns {Promise<Receipt | undefined>} The receipt object if found, undefined otherwise
  //  * @throws {ResponseArgsError} When the API request fails
  //  * @throws {z.ZodError} When parameter validation fails
  //  *
  //  * @example
  //  * const receipt = await service.fetchRemissionReturnReceipt({
  //  *   receiptId: '123',
  //  *   returnId: '456'
  //  * });
  //  */
  // async fetchRemissionReturnReceipt(
  //   params: FetchRemissionReturnParams,
  //   abortSignal?: AbortSignal,
  // ): Promise<Receipt | undefined> {
  //   this.#logger.debug('Fetching remission return receipt', () => ({ params }));

  //   const { receiptId, returnId } =
  //     FetchRemissionReturnReceiptSchema.parse(params);

  //   this.#logger.info('Fetching return receipt from API', () => ({
  //     receiptId,
  //     returnId,
  //   }));

  //   let req$ = this.#returnService.ReturnGetReturnReceipt({
  //     receiptId,
  //     returnId,
  //     eagerLoading: 2,
  //   });

  //   if (abortSignal) {
  //     this.#logger.debug('Request configured with abort signal');
  //     req$ = req$.pipe(takeUntilAborted(abortSignal));
  //   }

  //   const res = await firstValueFrom(req$);

  //   if (res?.error) {
  //     this.#logger.error(
  //       'Failed to fetch return receipt',
  //       new Error(res.message || 'Unknown error'),
  //     );
  //     throw new ResponseArgsError(res);
  //   }

  //   const receipt = res?.result as Receipt | undefined;
  //   this.#logger.debug('Successfully fetched return receipt', () => ({
  //     found: !!receipt,
  //   }));

  //   return receipt;
  // }

  /**
   * Fetches a remission return by its ID.
   * Validates parameters using FetchReturnSchema before making the request.
   *
   * @async
   * @param {FetchReturnParams} params - The parameters for fetching the return
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<Return | undefined>} The return object if found, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const returnData = await service.fetchReturn({ returnId: 123 });
   */
  async fetchReturn(
    params: FetchReturnParams,
    abortSignal?: AbortSignal,
  ): Promise<Return | undefined> {
    this.#logger.debug('Fetching remission return', () => ({ params }));

    const { returnId, eagerLoading = 2 } = FetchReturnSchema.parse(params);

    this.#logger.info('Fetching return from API', () => ({
      returnId,
    }));

    let req$ = this.#returnService.ReturnGetReturn({
      returnId,
      eagerLoading,
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to fetch return',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const returnData = res?.result as Return | undefined;
    this.#logger.debug('Successfully fetched return', () => ({
      found: !!returnData,
    }));

    return returnData;
  }

  /**
   * Creates a new remission return with the specified parameters.
   * Validates parameters using CreateReturnSchema before making the request.
   *
   * @async
   * @param {CreateReturn} params - The parameters for creating the return
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<ResponseArgs<Return> | undefined>} The created return object if successful, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const returnResponse = await service.createReturn({
   *   returnGroup: 'group1',
   * });
   */
  async createReturn(
    params: CreateReturn,
    abortSignal?: AbortSignal,
  ): Promise<ResponseArgs<Return> | undefined> {
    this.#logger.debug('Create remission return', () => ({ params }));

    const suppliers =
      await this.#remissionSupplierService.fetchSuppliers(abortSignal);
    const firstSupplier = suppliers[0];

    this.#logger.debug('Create remission return', () => ({
      params,
    }));

    let { returnGroup } = CreateReturnSchema.parse(params);

    // Wird gesetzt, wenn die Remission fortgesetzt wird nachdem man eine Wanne abgeschlossen hat
    // Ansonsten Default auf aktuelles Datum
    if (!returnGroup) {
      returnGroup = String(Date.now());
    }

    this.#logger.info('Create remission return from API', () => ({
      supplierId: firstSupplier.id,
      returnGroup,
    }));

    let req$ = this.#returnService.ReturnCreateReturn({
      data: {
        supplier: { id: firstSupplier.id },
        returnGroup,
      },
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to create return',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const returnResponse = res as ResponseArgs<Return> | undefined;
    this.#logger.debug('Successfully created return', () => ({
      found: !!returnResponse,
    }));

    return returnResponse;
  }

  /**
   * Creates a new remission return receipt with the specified parameters.
   * Validates parameters using CreateReceipt before making the request.
   *
   * @async
   * @param {CreateReceipt} params - The parameters for creating the receipt
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<ResponseArgs<Receipt> | undefined>} The created receipt object if successful, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const receiptResponse = await service.createReceipt({
   *   returnId: 123,
   *   receiptNumber: 'ABC-123',
   * });
   */
  async createReceipt(
    params: CreateReceipt,
    abortSignal?: AbortSignal,
  ): Promise<ResponseArgs<Receipt> | undefined> {
    this.#logger.debug('Create remission return receipt', () => ({ params }));

    const stock =
      await this.#remissionStockService.fetchAssignedStock(abortSignal);
    const suppliers =
      await this.#remissionSupplierService.fetchSuppliers(abortSignal);
    const firstSupplier = suppliers[0];

    const { returnId, receiptNumber } = params;

    this.#logger.info('Create remission return receipt from API', () => ({
      returnId,
      receiptNumber,
    }));

    let req$ = this.#returnService.ReturnCreateReceipt({
      returnId,
      data: {
        receiptNumber,
        stock: {
          id: stock.id,
        },
        supplier: {
          id: firstSupplier.id,
        },
        receiptType: 1, // Default to ShippingNote = 1
      },
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to create return receipt',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const receiptResponse = res as ResponseArgs<Receipt> | undefined;
    this.#logger.debug('Successfully created return receipt', () => ({
      found: !!receiptResponse,
    }));

    return receiptResponse;
  }

  /**
   * Assigns a package to the specified return receipt.
   * Validates parameters using AssignPackage before making the request.
   *
   * @async
   * @param {AssignPackage} params - The parameters for assigning the package
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<ResponseArgs<Receipt> | undefined>} The updated receipt object if successful, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const updatedReceipt = await service.assignPackage({
   *   returnId: 123,
   *   receiptId: 456,
   *   packageNumber: 'PKG-789',
   * });
   */
  async assignPackage(
    params: AssignPackage,
    abortSignal?: AbortSignal,
  ): Promise<ResponseArgs<Receipt> | undefined> {
    this.#logger.debug('Assign package to return receipt', () => ({ params }));

    const { returnId, receiptId, packageNumber } = params;

    this.#logger.info('Assign package from API', () => ({
      returnId,
      receiptId,
      packageNumber,
    }));

    let req$ = this.#returnService.ReturnCreateAndAssignPackage({
      returnId,
      receiptId,
      data: {
        packageNumber,
      },
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to assign package',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const receiptWithAssignedPackageResponse = res as
      | ResponseArgs<Receipt>
      | undefined;

    this.#logger.debug('Successfully assigned package', () => ({
      found: !!receiptWithAssignedPackageResponse,
    }));
    return receiptWithAssignedPackageResponse;
  }

  async removeReturnItemFromReturnReceipt(params: {
    returnId: number;
    receiptId: number;
    receiptItemId: number;
  }) {
    const res = await firstValueFrom(
      this.#returnService.ReturnRemoveReturnItem(params),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to remove item from return receipt',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }
  }

  /**
   * Cancels a return receipt and the associated return.
   * Validates parameters before making the request.
   *
   * @async
   * @param {Object} params - The parameters for the cancellation
   * @param {number} params.returnId - ID of the return to cancel
   * @param {number} params.receiptId - ID of the receipt to cancel
   * @return {Promise<void>} Resolves when the cancellation is successful
   * @throws {ResponseArgsError} When the API request fails
   */
  async cancelReturnReceipt(params: {
    returnId: number;
    receiptId: number;
  }): Promise<void> {
    const res = await firstValueFrom(
      this.#returnService.ReturnCancelReturnReceipt(params),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to cancel return receipt',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }
  }

  /**
   * Completes a single return receipt and the associated return.
   * Validates parameters before making the request.
   *
   * @async
   * @returns {Promise<Return>} The completed return object
   * @throws {ResponseArgsError} When the API request fails
   */
  async cancelReturn(params: { returnId: number }): Promise<void> {
    const res = await firstValueFrom(
      this.#returnService.ReturnCancelReturn(params),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to cancel return',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }
  }

  async deleteReturnItem(params: { itemId: number }) {
    this.#logger.debug('Deleting return item', () => ({ params }));
    const res = await firstValueFrom(
      this.#returnService.ReturnDeleteReturnItem(params),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to delete return item',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    return res?.result as ReturnItem;
  }

  async updateReturnItemImpediment(params: UpdateItemImpediment) {
    this.#logger.debug('Update return item impediment', () => ({ params }));

    const { itemId, comment } = UpdateItemImpedimentSchema.parse(params);

    const res = await firstValueFrom(
      this.#returnService.ReturnReturnItemImpediment({
        itemId,
        data: {
          comment,
        },
      }),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to update return item impediment',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    return res?.result as ReturnItem;
  }

  async updateReturnSuggestionImpediment(params: UpdateItemImpediment) {
    this.#logger.debug('Update return suggestion impediment', () => ({
      params,
    }));
    const { itemId, comment } = UpdateItemImpedimentSchema.parse(params);
    const res = await firstValueFrom(
      this.#returnService.ReturnReturnSuggestionImpediment({
        itemId,
        data: {
          comment,
        },
      }),
    );
    if (res?.error) {
      this.#logger.error(
        'Failed to update return suggestion impediment',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }
    return res?.result as ReturnSuggestion;
  }

  async completeReturnReceipt({
    returnId,
    receiptId,
  }: {
    returnId: number;
    receiptId: number;
  }): Promise<Receipt> {
    this.#logger.debug('Completing return receipt', () => ({ returnId }));
    const res = await firstValueFrom(
      this.#returnService.ReturnFinalizeReceipt({
        returnId,
        receiptId,
        data: {},
      }),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to complete return receipt',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    return res?.result as Receipt;
  }

  async completeReturn(params: { returnId: number }): Promise<Return> {
    this.#logger.debug('Completing return', () => ({
      returnId: params.returnId,
    }));

    const res = await firstValueFrom(
      this.#returnService.ReturnFinalizeReturn(params),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to complete return',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    this.#logger.info('Successfully completed return', () => ({
      returnId: params.returnId,
    }));

    return res?.result as Return;
  }

  async completeReturnGroup(params: { returnGroup: string }) {
    this.#logger.debug('Completing return group', () => ({
      returnId: params.returnGroup,
    }));

    const res = await firstValueFrom(
      this.#returnService.ReturnFinalizeReturnGroup(params),
    );

    if (res?.error) {
      this.#logger.error(
        'Failed to complete return group',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    this.#logger.info('Successfully completed return group', () => ({
      returnId: params.returnGroup,
    }));

    return res?.result as Return[];
  }

  async completeReturnReceiptAndReturn(params: {
    returnId: number;
    receiptId: number;
  }): Promise<Return> {
    this.#logger.debug('Completing return receipt and return', () => ({
      returnId: params.returnId,
      receiptId: params.receiptId,
    }));

    await this.completeReturnReceipt({
      returnId: params.returnId,
      receiptId: params.receiptId,
    });

    const completedReturn = await this.completeReturn({
      returnId: params.returnId,
    });

    this.#logger.info('Successfully completed return and receipt', () => ({
      returnId: params.returnId,
      receiptId: params.receiptId,
    }));

    return completedReturn;
  }

  /**
   * Adds a return item to the specified return receipt.
   * Validates parameters using AddReturnItemSchema before making the request.
   *
   * @async
   * @param {AddReturnItem} params - The parameters for adding the return item
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<ReceiptReturnTuple | undefined>} The updated receipt and return tuple if successful, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const updatedTuple = await service.addReturnItem({
   *   returnId: 123,
   *   receiptId: 456,
   *   returnItemId: 789,
   *   quantity: 10,
   *   inStock: 5,
   * });
   */
  async addReturnItem(
    params: AddReturnItem,
    abortSignal?: AbortSignal,
  ): Promise<ReceiptReturnTuple | undefined> {
    this.#logger.debug('Adding return item', () => ({ params }));

    const { returnId, receiptId, returnItemId, quantity, inStock } =
      AddReturnItemSchema.parse(params);

    this.#logger.info('Add return item from API', () => ({
      returnId,
      receiptId,
      returnItemId,
      quantity,
      inStock,
    }));

    let req$ = this.#returnService.ReturnAddReturnItem({
      returnId,
      receiptId,
      data: {
        returnItemId,
        quantity,
        inStock,
      },
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to add return item',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const updatedReturn = res?.result as ReceiptReturnTuple | undefined;
    this.#logger.debug('Successfully added return item', () => ({
      found: !!updatedReturn,
    }));

    return updatedReturn;
  }

  /**
   * Adds a return suggestion item to the specified return receipt.
   * Validates parameters using AddReturnSuggestionItemSchema before making the request.
   *
   * @async
   * @param {AddReturnSuggestionItem} params - The parameters for adding the return suggestion item
   * @param {AbortSignal} [abortSignal] - Optional signal to abort the request
   * @returns {Promise<ReceiptReturnSuggestionTuple | undefined>} The updated receipt and return suggestion tuple if successful, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const updatedTuple = await service.addReturnSuggestionItem({
   *   returnId: 123,
   *   receiptId: 456,
   *   returnSuggestionId: 789,
   *   quantity: 10,
   *   inStock: 5,
   *   impedimentComment: 'Restmenge',
   *   remainingQuantity: 5
   * });
   */
  async addReturnSuggestionItem(
    params: AddReturnSuggestionItem,
    abortSignal?: AbortSignal,
  ): Promise<ReceiptReturnSuggestionTuple | undefined> {
    this.#logger.debug('Adding return suggestion item', () => ({ params }));

    const {
      returnId,
      receiptId,
      returnSuggestionId,
      quantity,
      inStock,
      impedimentComment,
      remainingQuantity,
    } = AddReturnSuggestionItemSchema.parse(params);

    this.#logger.info('Add return suggestion item from API', () => ({
      returnId,
      receiptId,
      returnSuggestionId,
      quantity,
      inStock,
      impedimentComment,
      remainingQuantity,
    }));

    let req$ = this.#returnService.ReturnAddReturnSuggestion({
      returnId,
      receiptId,
      data: {
        returnSuggestionId,
        quantity,
        inStock,
        impedimentComment,
        remainingQuantity,
      },
    });

    if (abortSignal) {
      this.#logger.debug('Request configured with abort signal');
      req$ = req$.pipe(takeUntilAborted(abortSignal));
    }

    const res = await firstValueFrom(req$);

    if (res?.error) {
      this.#logger.error(
        'Failed to add return suggestion item',
        new Error(res.message || 'Unknown error'),
      );
      throw new ResponseArgsError(res);
    }

    const updatedReturnSuggestion = res?.result as
      | ReceiptReturnSuggestionTuple
      | undefined;
    this.#logger.debug('Successfully added return suggestion item', () => ({
      found: !!updatedReturnSuggestion,
    }));

    return updatedReturnSuggestion;
  }

  /**
   * Warenbegleitschein eröffnen
   * Creates a remission by generating a return and receipt.
   * Validates parameters using CreateRemissionSchema before making the request.
   *
   * @async
   * @param {CreateRemission} params - The parameters for creating the remission
   * @returns {Promise<CreateRemission | undefined>} The created remission object if successful, undefined otherwise
   * @throws {ResponseArgsError} When the API request fails
   * @throws {z.ZodError} When parameter validation fails
   *
   * @example
   * const remission = await service.createRemission({
   *   returnId: 123,
   *   receiptId: 456,
   * });
   */
  async createRemission({
    returnGroup,
    receiptNumber,
  }: {
    returnGroup: string | undefined;
    receiptNumber: string | undefined;
  }): Promise<CreateRemission | undefined> {
    this.#logger.debug('Create remission', () => ({
      returnGroup,
      receiptNumber,
    }));

    const createdReturn: ResponseArgs<Return> | undefined =
      await this.createReturn({
        returnGroup,
      });

    if (!createdReturn || !createdReturn.result) {
      this.#logger.error('Failed to create return for remission');
      return;
    }

    const createdReceipt: ResponseArgs<Receipt> | undefined =
      await this.createReceipt({
        returnId: createdReturn.result.id,
        receiptNumber,
      });

    if (!createdReceipt || !createdReceipt.result) {
      this.#logger.error('Failed to create return receipt');
      return;
    }

    const invalidProperties = {
      ...createdReturn.invalidProperties,
      ...createdReceipt.invalidProperties,
    };

    this.#logger.info('Successfully created remission', () => ({
      returnId: createdReturn.result.id,
      receiptId: createdReceipt.result.id,
    }));

    return {
      returnId: createdReturn.result.id,
      receiptId: createdReceipt.result.id,
      invalidProperties,
    };
  }

  /**
   * Remits an item to the return receipt based on its type.
   * Determines whether to add a return item or return suggestion item based on the remission item type.
   *
   * @async
   * @param {Object} params - The parameters for remitting the item
   * @param {number} params.itemId - The ID of the item to remit
   * @param {Omit<AddReturnItem, 'returnItemId'> | Omit<AddReturnSuggestionItem, 'returnSuggestionId'>} params.addItem - The item data to add (without the item ID field)
   * @param {RemissionItemType} params.type - The type of remission item (ReturnItem, ReturnSuggestion, or Unknown)
   * @returns {Promise<ReceiptReturnSuggestionTuple | ReceiptReturnTuple | undefined>} The updated receipt and return tuple if successful, undefined otherwise
   *
   * @example
   * // Remit a ReturnItem
   * const result = await service.remitItem({
   *   itemId: 123,
   *   addItem: {
   *     returnId: 1,
   *     receiptId: 2,
   *     quantity: 10,
   *     inStock: 5,
   *   },
   *   type: RemissionItemType.ReturnItem,
   * });
   *
   * @example
   * // Remit a ReturnSuggestion
   * const result = await service.remitItem({
   *   itemId: 456,
   *   addItem: {
   *     returnId: 1,
   *     receiptId: 2,
   *     quantity: 10,
   *     inStock: 5,
   *     impedimentComment: 'Restmenge',
   *     remainingQuantity: 5,
   *   },
   *   type: RemissionItemType.ReturnSuggestion,
   * });
   */
  async remitItem({
    itemId,
    addItem,
    type,
  }: {
    itemId: number;
    addItem:
      | Omit<AddReturnItem, 'returnItemId'>
      | Omit<AddReturnSuggestionItem, 'returnSuggestionId'>;
    type: RemissionItemType;
  }): Promise<ReceiptReturnSuggestionTuple | ReceiptReturnTuple | undefined> {
    if (type === RemissionItemType.Unknown) {
      this.#logger.error(
        'Invalid remission item type: None. Cannot remit item.',
      );
      return;
    }

    // ReturnSuggestion
    if (type === RemissionItemType.ReturnSuggestion) {
      return await this.addReturnSuggestionItem({
        returnId: addItem.returnId,
        receiptId: addItem.receiptId,
        returnSuggestionId: itemId,
        quantity: addItem.quantity,
        inStock: addItem.inStock,
        impedimentComment: (addItem as AddReturnSuggestionItem)
          .impedimentComment,
        remainingQuantity: (addItem as AddReturnSuggestionItem)
          .remainingQuantity,
      });
    }

    // ReturnItem
    if (type === RemissionItemType.ReturnItem) {
      return await this.addReturnItem({
        returnId: addItem.returnId,
        receiptId: addItem.receiptId,
        returnItemId: itemId,
        quantity: addItem.quantity,
        inStock: addItem.inStock,
      });
    }

    return;
  }
}
