import { AvailabilityRequestDTO } from '@generated/swagger/availability-api';
import {
  GetAvailabilityParams,
  GetB2bDeliveryAvailabilityParams,
  GetDeliveryAvailabilityParams,
  GetDigDeliveryAvailabilityParams,
  GetDownloadAvailabilityParams,
  GetInStoreAvailabilityParams,
  GetPickupAvailabilityParams,
} from '../schemas';
import { Price } from '@isa/common/data-access';

/**
 * Adapter for converting validated availability params to API request format.
 *
 * Maps domain params to AvailabilityRequestDTO[] format required by the generated API client.
 */
export class AvailabilityRequestAdapter {
  /**
   * Maps optional price object to API format.
   * Extracts value and VAT information from domain price structure.
   */
  private static mapPrice(price?: Price): AvailabilityRequestDTO['price'] {
    if (!price) return undefined;

    return {
      value: price.value
        ? {
            value: price.value.value,
            currency: price.value.currency,
            currencySymbol: price.value.currencySymbol,
          }
        : undefined,
      vat: price.vat
        ? {
            value: price.vat.value,
            inPercent: price.vat.inPercent,
            label: price.vat.label,
            vatType: price.vat.vatType,
          }
        : undefined,
    };
  }

  /**
   * Converts Pickup availability params to API request format.
   * Uses store availability endpoint with branch context.
   */
  static toPickupRequest(
    params: GetPickupAvailabilityParams,
  ): AvailabilityRequestDTO[] {
    return params.items.map((item) => ({
      ean: item.ean,
      itemId: String(item.itemId),
      qty: item.quantity,
      shopId: params.branchId,
      price: this.mapPrice(item.price),
    }));
  }

  /**
   * Converts B2B delivery params to API request format.
   * Uses store availability endpoint (like Pickup) with branch context.
   * Note: Logistician will be overridden to '2470' by the service layer.
   *
   * @param params B2B availability params (no shopId - uses default branch)
   * @param shopId The default branch ID to use (fetched by service)
   */
  static toB2bRequest(
    params: GetB2bDeliveryAvailabilityParams,
    shopId: number,
  ): AvailabilityRequestDTO[] {
    return params.items.map((item) => ({
      ean: item.ean,
      itemId: String(item.itemId),
      qty: item.quantity,
      shopId: shopId,
      price: this.mapPrice(item.price),
    }));
  }

  /**
   * Converts standard Delivery params to API request format.
   * Uses shipping availability endpoint.
   */
  static toDeliveryRequest(
    params: GetDeliveryAvailabilityParams,
  ): AvailabilityRequestDTO[] {
    return params.items.map((item) => ({
      ean: item.ean,
      itemId: String(item.itemId),
      qty: item.quantity,
      price: this.mapPrice(item.price),
    }));
  }

  /**
   * Converts DIG delivery params to API request format.
   * Uses shipping availability endpoint (same as standard Delivery).
   */
  static toDigDeliveryRequest(
    params: GetDigDeliveryAvailabilityParams,
  ): AvailabilityRequestDTO[] {
    return params.items.map((item) => ({
      ean: item.ean,
      itemId: String(item.itemId),
      qty: item.quantity,
      price: this.mapPrice(item.price),
    }));
  }

  /**
   * Converts Download params to API request format.
   * Uses shipping availability endpoint with quantity forced to 1.
   */
  static toDownloadRequest(
    params: GetDownloadAvailabilityParams,
  ): AvailabilityRequestDTO[] {
    return params.items.map((item) => ({
      ean: item.ean,
      itemId: String(item.itemId),
      qty: 1, // Always 1 for downloads
      price: this.mapPrice(item.price),
    }));
  }

  /**
   * Main routing method - converts availability params to API request format.
   * Automatically selects the correct conversion based on orderType.
   *
   * Notes:
   * - B2B-Versand is not supported by this method as it requires a separate
   *   shopId parameter (default branch ID). Use toB2bRequest() directly instead.
   * - Rücklage (InStore) is not supported by this method as it uses the stock
   *   service directly, not the availability API.
   */
  static toApiRequest(
    params: Exclude<
      GetAvailabilityParams,
      GetB2bDeliveryAvailabilityParams | GetInStoreAvailabilityParams
    >,
  ): AvailabilityRequestDTO[] {
    switch (params.orderType) {
      case 'Abholung':
        return this.toPickupRequest(params);
      case 'Versand':
        return this.toDeliveryRequest(params);
      case 'DIG-Versand':
        return this.toDigDeliveryRequest(params);
      case 'Download':
        return this.toDownloadRequest(params);
      default: {
        const _exhaustive: never = params;
        throw new Error(
          `Unsupported order type: ${JSON.stringify(_exhaustive)}`,
        );
      }
    }
  }
}
