import { inject, Injectable } from '@angular/core';
import {
  OrderService,
  OrderDTO,
  DisplayOrderDTO,
} from '@generated/swagger/oms-api';
import { ResponseArgsError, takeUntilAborted } from '@isa/common/data-access';
import { logger } from '@isa/core/logging';
import { firstValueFrom } from 'rxjs';

@Injectable({ providedIn: 'root' })
export class OrdersService {
  #logger = logger(() => ({ service: 'OrdersService' }));
  #orderService = inject(OrderService);

  /**
   * Fetch a single order by its numeric ID
   */
  async getOrder(
    orderId: number,
    abortSignal?: AbortSignal,
  ): Promise<OrderDTO | null> {
    let req$ = this.#orderService.OrderGetOrder(orderId);

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

    const res = await firstValueFrom(req$);

    if (res.error) {
      const error = new ResponseArgsError(res);
      this.#logger.error('Failed to fetch order', { orderId, error });
      throw error;
    }

    return res.result ?? null;
  }

  /**
   * Fetch multiple orders by their numeric IDs
   * Uses Promise.all to fetch orders concurrently
   */
  async getOrders(
    orderIds: number[],
    abortSignal?: AbortSignal,
  ): Promise<OrderDTO[]> {
    if (!orderIds.length) {
      return [];
    }

    const promises = orderIds.map((orderId) =>
      this.getOrder(orderId, abortSignal),
    );

    const results = await Promise.all(promises);

    // Filter out null results (failed fetches)
    return results.filter((order): order is OrderDTO => order !== null);
  }

  /**
   * Fetch a single display order by its numeric ID
   */
  async getDisplayOrder(
    orderId: number,
    abortSignal?: AbortSignal,
  ): Promise<DisplayOrderDTO | null> {
    let req$ = this.#orderService.OrderGetDisplayOrder(orderId);

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

    const res = await firstValueFrom(req$);

    if (res.error) {
      const error = new ResponseArgsError(res);
      this.#logger.error('Failed to fetch display order', { orderId, error });
      throw error;
    }

    return res.result ?? null;
  }

  /**
   * Fetch multiple display orders by their numeric IDs
   * Uses Promise.all to fetch orders concurrently
   */
  async getDisplayOrders(
    orderIds: number[],
    abortSignal?: AbortSignal,
  ): Promise<DisplayOrderDTO[]> {
    if (!orderIds.length) {
      return [];
    }

    const promises = orderIds.map((orderId) =>
      this.getDisplayOrder(orderId, abortSignal),
    );

    const results = await Promise.all(promises);

    // Filter out null results (failed fetches)
    return results.filter((order): order is DisplayOrderDTO => !!order);
  }
}
